AutoSave Form Fields using jQuery – .change(), focusout() and the deferred .when() functions

I have been prototyping some general approaches, some new functionality, and other various concepts, all part of how a larger system will work. After seeing some interesting and nostalgic things being done with jQuery, it gave me an idea for an approach that may be suitable to achieve some delayed asynchronous actions. Thanks to Aaron Powell for those neat walk-throughs.

My Idea is probably even simpler but focussed more around having elements of a form “submit themselves” in a way making use of new features of jQuery 1.5. I have not yet completed the polished version of this functionality, where it will handle errors and other complexities to be a robust solution. I do believe this approach does align with the progressive enhancement objectives of good websites, if a clients browser does not support this functionality there is still a standard submission of the form data available. But none-the-less would like to share/document my approach and direction.

Basic Flow

  1. User types-in/modifies an input field.
  2. jQuery code detects this.
  3. Asynchronously sends this piece of data.
  4. Provide elegant feedback when this is complete.

Improved flow (a future exercise)

  • Step 2 above, should count down and reset counting if that same field is changed before the data is sent. Still a “to do” item.
  • Step 4 isn’t exactly elegant at the moment; a confirmation message or icon shows up, which is rather crude.

Demo

Again thanks to Aaron for reminding me of the awesome site: jsFiddle, I used it to speed up my jQuery experiments without relying on Visual Studio and running an MVC application to create and test the jQuery logic.

$(':input').change(function() {
    var c = $(this);
    $.when(
    c.focusout()).then(function() {
        $('#last-action').append(c.attr('name') + ' = ' + c.val() + '<br />');
    });
});

Here is the jsFiddle demo of this functionality, simply type in any of the input boxes, and tab away and see the results be “submitted”. Of course no submit code is firing yet, we’ll look at that now.

Let’s refactor a little to support some more important functionality to get ready to submit our form. The line in particular about just appending the data can be replaced with a function to handle submitting the form, and just for the demo it will also still output the data in the little debug div. This is where I make use of Aaron’s demonstration of the recursive setTimeout pattern.

$(':input').change(function() {
    var c = $(this);
    $.when(
    c.focusout()).then(function() {
        startCountDownAndSendData(c, 5) //delay by 5 seconds
    });
});

With this function, we’re going to supply the html element (c) and an integer (waitDuration) representing how many seconds to wait before “submitting”.

function startCountDownAndSendData(c, waitDuration) {
    function go(){
        if(waitDuration <= 0) //count down from a supplied duration value (in seconds)
        {
            $('#last-action').append(c.attr('name') + ' = ' + c.val() + '<br />');
            $('form#MyFormId').trigger('submit');
            return;
        }
        waitDuration--;
        setTimeout(go, 1000);
    }
    go();
}

You can see this refactoring in operation here, but it won’t submit anywhere, that’s what we will handle next time in a post about Asynchronous MVC controllers. So steps from 3 and 4 are still to demonstrate to you dear reader, stay tuned… part two is here.

Advertisements

Using jQuery Templates to .appendTo() an <option> on a <select> list via .render()

I couldn’t find a good example that shows how to achieve this, so I thought I would quickly outline the process along with some “gotchas” I encountered.

First, an outline of the technology/components/elements I’m talking about:

  • Templates is the Microsoft proposed templating solution for jQuery.
  • This library can be obtained from github.
  • I want to add <options> on the <select> list.
  • I want to achieve this using the .render() method demonstrated on ScottGu‘s blog post on jQuery Templates.
  • In conjunction with using the .appendTo() method in jQuery.

The desired end result, outputting items into the select list via jQuery:
Select List

There’s actually several similar ways this can be achieved as can be seen on this StackOverflow question. I’ve put a summary of this post as an answer on that question also.

To add scope to this post, here is a quote from Scott Gu’s blog post on the purpose of the templating system.

Client-side templates enable jQuery developers to easily generate and render HTML UI on the client. Templates support a simple syntax that enables either developers or designers to declaratively specify the HTML they want to generate. Developers can then programmatically invoke the templates on the client, and pass JavaScript objects to them to make the content rendered completely data driven. These JavaScript objects can optionally be based on data retrieved from a server.

At this point I’m going forward on the assumption you now have a rough understanding of the purpose of templating so I can focus primarily on getting this to work with a <select> list.

The first step is to setup the appropriate template structure. In this scenario, it’s the <option> block with the ‘value’ and ‘text’ properties needing substitution. The syntax for the substitution variables is wrapped by the two opening curly-braces and an equal sign, it’s name then followed by 2 closing curly-braces. A note here as this is JavaScript performing the substitutions, it is in fact case sensitive.

<script id="templateOptionItem" type="text/html">
    <option value=\'{{= Value}}\'>{{= Text}}</option>
</script>

Zoom in, enhance!

Ensure you escape single quotes

Ensure you escape single quotes otherwise the templating render() action will fail.

The next step is to “fetch” your data (input data), in my real world example this comes back as JSON. But for now let’s just hard code the data array.

    function renderTest() {

        var someData = [
            { Text: "one", Value: "1" },
            { Text: "two", Value: "2" },
            { Text: "three", Value: "3"}];

        //on the template, apply the render with the data input, and then append to the html element.
        $("#templateOptionItem").render(someData).appendTo("#theSelectList");
    }

That last line with the .render() and .appendTo() is where the elegance lies, the set-up of reusable templates is extracted out of the actual call to map the data to the html elements. There are more features in the templating library, so check out this post for more examples.

The aim is to keep this post on the very narrow topic of just applying to a select list. So the actual implementation of the ajax-y request and response of JSON will come in a future post. The impact on the actual templating logic is trivial and limited to the what you pass to the .render() call.

Summary of the gothcas:

  • Escape your quotes (single and doubles).
  • The template must be in it’s own script block, not as a JavaScript var (string). Not sure why that is, I’m still investigating.
  • Ensure your selectors are working.
  • Ensure your output is wrapped in valid html elements, at the least a <div>.
  • Template place holders are case-sensitive.