InfoPath - disabling backspace key in browser form

How to disable the backspace key using Javascript/jQuery for an InfoPath browser form in SharePoint 2010.

 

The problem

One really troubling problem with almost all web solutions is how the Backspace key works.  By default, it tells your browser to go back to the previous page in history.

If you are just browsing around on your Intranet, this is probably not a big deal - firstly, you wouldn't be pressing backspace unless you actually wanted to go back.  Secondly, if you did indeed made a mistake and pressed the backspace key, you'd just undo that action by clicking the forward button, or navigate to another link.  No problem.

 

When you are filling in a form on the browser though, such as through InfoPath, suddenly the backspace key is a big deal.  You users may be using the backspace key to delete text that they are in the middle of entering.  And if they didn't have a textbox focused, the backspace key is sent to the browser form, and suddenly you have a problem.  The form disappeared, and you have lost information.

 

InfoPath is quite smart - it remembers which view you are supposed to be on, and when you navigate to an outdated browser historical view of the form - Form Server will automatically redirect you forward to show you the correct form you are supposed to be viewing.  This is good, at least in the navigation sense.  So the only remaining problem is the lost data - your user may have had a whole page filled out and this mistake has just cleared their form.  Not good.

 

Enter Javascript

So, the plan is simple:

  1. Inject javascript to the existing browser form
  2. Listen to keydown event for a backspace key (keycode 8)
  3. Eat the event and stop it from propagation, so the browser don't see it

Using jQuery, you'll need this simple function.

 

function document_keydown(e) {
    if (e.keyCode == 8 && e.target.tagName != "INPUT") {

        // letting us know we've ate a backspace key
        SP.UI.Notify.addNotification('Ate a backspace key, hew!', false);

        // cancel backspace navigation
        e.preventDefault();
        e.stopImmediatePropagation();
        return false;
    }
};

$(document).keydown(document_keydown);

 

Injecting Javascript in modal dialog

 

If you are using SharePoint 2010's modal dialog to show InfoPath in a modal popup, it's slightly trickier.

 

// grab a reference to the modal window object in SharePoint
var w = SP.UI.ModalDialog.showModalDialog(options);

if (w) {
    // get the modal window's iFrame element
    var f = w.get_frameElement();

    // watch frame's readyState change - when page load is complete, re-attach keydown event
    // on the new document       
    f.onreadystatechange = function(e) {
        if (f.readyState == 'complete') {
            var fwin = f.contentWindow || f.contentDocument;
            $(fwin.document).keydown(document_keydown);
        }
    };
}

Result

 

nom-nom-nom backspace keys.

image

 

Note, because the Javascript catches the keypress event at the document level.  If your user still has focus on the input (textbox) level, the event will not be stopped - so your user still will be able to backspace when they are using a textbox.

AUSPC 2012 summary

I had an awesome time presenting Building your own custom REST Services and consuming them with jQuery AJAX in the Australian SharePoint Conference 2012.  A big thank you to the developers that came and geeked out with me for an hour on a Wednesday afternoon.

Notes

When you build a custom WCF Service using the CKS template, it is deployed to a subfolder the web front end's ISAPI folder, which, in turn, is mapped to the site's /_vti_bin/ folder.

image

 

It appears that in my earlier attempt to create an incomplete version of the REST service template item, I interfered with how CKS's templates worked - and correct features for deploying the WCF service is no longer being included in the package.  While existing items were updated and deployed, the new WCF service that I was creating wasn't being deployed to the ISAPI folder.

I've removed the REST template item from my Visual Studio .NET environment, and voila - the WCF services deployed nicely once again.

So that's one mystery resolved.  Now I scratch my head about how to fix my VS.NET REST template item.

 

Downloads

AUSPC 2012 quick update

I'm in the strange and calm interlude between day 1 and day 2 of awesomeness in the annual Australian SharePoint Conference (AUSPC) 2012.

Day 1 has been a lot of fun.  Manned the user group booth in the morning with Dan Brown.  Met many of the SharePoint guys in the community that I haven't seen for the last 6 month to a year.  Talked to a number of vendors, and attended a number of awesome sessions on the developer track.

I also got to sit on the panel answering developer questions amongst the legends like Nick Hadlee, Ishai Sagi, Brian Farnhill and Jeremy Thake

The oddest part is probably with MCA SharePoint Wayne Ewington sitting in the audience.  Every time we said something silly he'd start shaking his head and we'd all stop.  Hilarious.

 

Tomorrow morning, my session on Building your own custom REST Service and consuming them with jQuery AJAX is running in the developer track at 10:30am.  Hope to see everyone there.

All my related resources and presentations on this topic are summarized on /rest

Knockout binding formatters for date and currency

 

Dependency

  • Requires Knockout
  • jQuery (for setting text())
  • ASP.NET (for the formatting functions).

 

ko.bindingHandlers.date = {
    update: function(element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor(), allBindings = allBindingsAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
       
        var d = "";
        if (valueUnwrapped) {
            var m = /Date\([\d+-]+\)/gi.exec(valueUnwrapped);
            if (m) {
                d = String.format("{0:dd/MM/yyyy}", eval("new " + m[0]));
            }
        }       
        $(element).text(d);   
    }
};
ko.bindingHandlers.money = {
    update: function(element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor(), allBindings = allBindingsAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
       
        var m = "";
        if (valueUnwrapped) {       
            m = parseInt(valueUnwrapped);
            if (m) {
                m = String.format("{0:n0}", m);
            }
        }       
        $(element).text(m);   
    }
};

Usage:

 

  • data-bind="money: myMoney"
  • data-bind="date: myDate"

 

Note:

Dates are converted from ASP.NET's date format: \/Date(1000+1000)\/

InfoPath - creating sequential filenames without an extra column

Avid InfoPath form creators will no doubt know the trick to create sequential numbers for use in filenames.  The steps typically includes:

  1. Create a field FileName, create another field SeqNo.
  2. Publish the form to SharePoint Form library, and promote the column for SeqNo
  3. Create a view, use REST data connection or use owssrv.dll to get data from this Form library, in particular we want to know the SeqNo
  4. Prior to save, check that the FileName is not blank, query the data connection to find the latest SeqNo from the forms library.  Using max()
  5. Add one to this number, store it in SeqNo
  6. Create FileName by concatenating some prefix with SeqNo:  MyFile-004
  7. Submit through a data connection back to the Form library with the FileName

 

This blog post is NOT about using a second column

We will work out the next number completely without promoting any fields.

WHY, you may ask.  Well, because it's FUN!

And we get to play with a modified double-eval trick as a bonus!

 

Set up

  • Create a basic form, create a field filename
  • Publish to SharePoint Form library

image


image

 

Secondary data source for querying existing filenames

Create a SharePoint connection to the Form library.

Here I'm creating a SharePoint List data connection.  The old trick with owssrv.dll will work as well.

image

 

 

Secondary data source for submit (to save forms)

Another SharePoint connection to the Form library, this one is for submit.  Allow overwrite.  Also, use the filename field for saving.

image

image

Save button

Create a save button.  When the user clicks save, we're going to create a new filename with a sequential number, then call the submit data connection.

Our secondary data looks like this:

image

I drop this onto the form to show what is the data in this data connection.

 

image

 

What we want to do, is to take the names, strip out all the non-numeric characters, and then perform a max() operation to find the largest number.

 

Stripping characters with TRANSLATE

InfoPath has a useful function translate("abc", "ABC") it replaces the first set of characters with the second set.  If your second set is empty, like this: translate("abc", "") you can essentially perform a character removal.

And now, I can use my translate function like this:

image

image

Run the form in preview: we are now left with just the the numbers in the filename.  Good.

 

Double-eval

Back to our list of existing form names. 

image

The double-eval trick essentially gives us a way to do a for-each parse through a repeating section in InfoPath.

The basic form this is:

image

The inner-eval, runs "." (current), and the outer-eval, runs ".." (parent).   Combined, this gives us a concatenated string of all the Title

image

 

Combine both the translate strip, and the double-eval, we get:

image

 

Preview:

image

 

Finally, replace the outer-eval with a max function, and prefix a 0 (for filenames that don't have numbers).

image

max(eval(Title, 'concat("0", translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz -+,_!.", ""))'))

 

Preview result:

image

 

So my filename function is this:

concat("form-", max(eval(Title, 'concat("0", translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz -+,_!.", ""))')) + 1 )

image

 

Here's the form running in Form Server

image

 

Download