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

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)\/

SSPUG retrospective: Creating Knockout user experiences in SharePoint with JavaScript

 

I had an absolute blast presenting Knockout, AJAX, jQuery, SP2010 REST services, and spservices tonight at the February 2012 Sydney SharePoint user group.

The turn out was awesome, and I want to thank you guys for the great questions and the awesome attention for listening me talk about this stuff, with great excitement, for 1.5 hours.

This is what we built, not bad, in 90 minutes ;-)

image

 

Great questions:

Why do you need to call ko.utils.unwrapObservable for the key function? 

This is actually pretty important, and I didn't explain it very well until I thought about it afterwards.

The reason is that I believe Knockout is actually building a dependency graph when you use knockout expressions and compute functions.  If you use data.Id() - you will actually set up a dependency chain between the knockout viewmodel and the key function.  I can't imagine it would be disastrously bad - since you don't bind the key function to the UI, but it is an unnecessary performance hit.

 

 

What do you do with the formatting?

The easiest way, I think, is to build a compute function and then return the value you want in the right format you wanted it.  Knockout itself doesn't contain formatting functions, and I think it will probably be implemented as an separate plugin.

ASP.NET's built in JavaScript, which is available in SharePoint, contains a lot of formatting functions for rendering both currency and dates. 

A separate, slightly prettier technique, is to add additional binding handlers (aka, the text:, html:, value: expressions), and create a new binding expression that also does formatting.  In my projects, I've used

  • money: MyCurrency
  • date: MyDate

These are one-way binding, because I'm lazy, but you can make them two-way as well if you want to handle the parsing.

 

Downloads

 

Next Presentations

No idea, but I plan to be presenting this for the rest of the year in the various SharePoint Saturdays, so bring your colleagues for a exciting session on a very cool, new technique.

SharePoint - JavaScript current page context info

Quick blog. On every SharePoint page there's a javascript context variable:

 _spPageContextInfo 
{
webServerRelativeUrl : "/ProjectWeb",
webLanguage : 1033,
currentLanguage : 1033,
webUIVersion : 4,
pageListId : "{c1d7b89f-f07b-4e2e-b89c-76c315831d59}",
pageItemId : 5,
userId : 68,
alertsEnabled : true,
siteServerRelativeUrl : "/",
allowSilverlightPrompt : "True"
}
So if you are on /ProjectWeb/Pages/default.aspx
_spPageContextInfo.pageListId;   // list guid for Pages
_spPageContextInfo.pageItemId; // ID for listitem

 

Special Note

siteServerRelativeUrl will tell you if your site collection is sitting at the root level, or mapped further down.  Fairly useful information for all sorts of mischief.

No idea why alertsEnabled is a useful information.

 

An Example

Say if you want to show the versions page:

var options = {
tite: "Version History",
url: _spPageContextInfo.webServerRelativeUrl + "/_layouts/Versions.aspx?list="+ _spPageContextInfo.pageListId +"&ID="+ _spPageContextInfo.pageItemId,
width: 800,
height: 500,
};
SP.UI.ModalDialog.showModalDialog(options);

 

This will get you the Version History page in a modal popup, without running any additional client context async query.

image

Figure: Version History showing in a modal popup.