Link here

Link here

Introducing Knockout, a UI library for JavaScript

Javascript, Knockout, UI 21 Comments »

Knockout is a JavaScript library that makes it easier to create rich, desktop-like user interfaces with JavaScript and HTML, using observers to make your UI automatically stay in sync with an underlying data model. It works particularly well with the MVVM pattern, offering declarative bindings somewhat like Silverlight but without the browser plugin.

So, what distinguishes this from all the other similar-sounding JavaScript libraries? (I blogged about an MVC/templating system for JavaScript back in 2007, Microsoft has suggested a data linking system for jQuery, and Google’s full of MVC-on-the-client toolkits.)

Well, Knockout combines some different ideas that open up very powerful possibilities:

  • Automatic dependency tracking: At the heart of Knockout is a system of observable variables and other variables computed as functions of them. For example, if you have firstName and lastName and then define fullName by concatenating these together, the framework knows that whenever either firstName or lastName changes, it must re-evaluate fullName. You don’t have to configure this – it’s inferred from your code execution, even if you have chains of observables referencing other observables.
    This makes it easy to build sophisticated view models in which changes to a few key properties automatically ripple out to all other affected parts of the model.
  • Declarative bindings: By adding a data-* attribute (part of the HTML 5 spec, and works fine in older browsers, including IE 6) you can quickly bind appearance and behaviour in your HTML to properties on a view model. For example, you can write <span data-bind="text: fullName"></span>, and then the element will display the value in your model property as text, automatically updating if any of the underlying data changes. Besides text, I’ve included a range of commonly useful declarative bindings (e.g., visible, click, and css), and you can easily plug in custom ones.
  • Nested templates: When you have a rich structure of view model data to display, it makes sense to display it using a template to keep your code simple. Knockout handles this easily by letting you bind a DOM node to a template and some data. Whenever either changes, the template gets re-rendered and your UI is updated. You can use data-bind attributes from inside templates (referencing any variable in scope at that point during template execution, such as foreach loop variables) to concisely add further interactivity. Plus, you can bind to templates from within templates, creating chains of nested templates. Because of how dependency tracking works, if the underlying data changes, Knockout knows it only needs to re-render the innermost templates affected by the change, so it’s efficient. Knockout uses the jquery-tmpl template engine by default, but you can plug in another template engine if you prefer some other template syntax.

These features together, combined with following the MVVM design pattern, mean you can apply sophisticated UI behaviours in a clean, concise, and organized way. It’s also possible to combine custom bindings and templates to create reusable controls (or plugins).

Extremely Trivial Example

OK, code. You could set up a view model as follows:

<script type="text/javascript">
    var myViewModel = {
        personName : ko.observable("Bert") // Initial state
    };
</script>

Then, you could bind it to an HTML UI as follows:

Enter your name:
<input id="source" data-bind="value: personName, valueUpdate: 'keyup'" />
 
<div data-bind="visible: personName().length > 5">
    Wow, what a long name you have.
</div>

Now, the text box will take its value from personName, and will automatically update its value whenever personName changes. The binding is two-way, so when you type into the text box, this updates personName.

The DIV with the “what a long name” message will be made visible whenever the name length exceeds 5 characters, and hidden otherwise. By referencing an observable value in a binding, you’ve implicitly set up notifications.

But I can just do that with jQuery!

Yes, we all love jQuery! It’s a fantastic replacement for the hideous DOM API we had to work with before.

The point of Knockout is not to replace jQuery – I expect most people who use Knockout will use jQuery too. The point is to make it easy to have one coherent underlying data model and then bind your UI to that. Change the data model and the UI changes, and vice-versa. That way, you don’t get complicated event handlers that have to update loads of different parts of the DOM to keep the UI up-to-date; instead, when you just change the underlying data model, you know all the affected UI gets updated. This also makes client-server interactions much easier: when saving data, you don’t have to try to scrape the current state off a load of DOM elements – you’ve already got it in a clean model. Likewise when loading data from the server and wanting to update the DOM to match – just push it into the data model and the UI is updated. It’s the MVVM pattern, much beloved of Silverlight developers.

A More Detailed Tutorial

Right, getting beyond “hello world” but still keeping things simple, let’s make a simple list editor. This will demonstrate some of Knockout’s core features – observables and bindings (though we’ll ignore templating for now – you can learn about that from other examples).

To get started, create an HTML file that references knockout.js or knockout-min.js and define a simple view model class. In JavaScript, any function can act as a class constructor. The following one has a single property which represents the items in a list.

<html>
<head>
    <script type="text/javascript" src="knockout.js"></script>
</head>
<body>	
    <script type="text/javascript">
        var listEditorViewModel = function () {
            // ko.observableArray lets you track changes to a collection of things
            this.allItems = ko.observableArray(["Apple", "Banana", "Cherry"]);
        };
    </script>
</body>
</html>

Next, let’s display the list on the screen. You can do that by creating an HTML <select> element and binding its contents to a model property using Knockout’s options binding:

<div>List items:</div>
<select multiple="multiple" data-bind="options: allItems"></select>
<script type="text/javascript">
    var listEditorViewModel = function () {
        ... as before ...
    };
 
    ko.applyBindings(document.body, new listEditorViewModel());
</script>

If you open this in a browser, you’ll see the list items:

image1 

What about letting the user add some more items to the list? Update the view model class so that it has another property for tracking the new item a user is adding, and add a method that pushes the new item into the array:

var listEditorViewModel = function () {
    // ko.observableArray lets you track changes to a collection of things
    this.allItems = ko.observableArray(["Apple", "Banana", "Cherry"]);
 
    // ko.observable tracks a single item. The initial state here is an empty string.
    this.itemToAdd = ko.observable("");
 
    this.addItem = function () {
        this.allItems.push(this.itemToAdd());
        this.itemToAdd(""); // After adding an item, reset itemToAdd to an empty string 
    }
};

Next we need to add some UI elements and bind them to these new model members.

<form data-bind="submit: addItem">
    Add item:
    <input data-bind="value: itemToAdd" />
    <button type="submit">Add</button>
</form>

That will do it! Now when the user edits the text box, its value automatically goes into the itemToAdd observable because of the value binding. When they submit the form, this invokes addItem() because of the submit binding. In turn, this updates allItems in the view model, and this automatically causes the on-screen list to be updated because its collection of options is bound to that model property. With Knockout, you don’t have to remember which parts of the UI to update following an event – you just change properties on the underlying view model, and anything bound to those properties will be notified and updated.

image2

Next thing, we might want to let the user remove items. We should let them select multiple items at once, then have a “remove” button that removes them all. First, we need to know what the user has got selected, so add a new view model property to represent selection, and bind it to the HTML element using Knockout’s selectedOptions binding.

<select multiple data-bind="options: allItems, selectedOptions: selectedItems"></select>
var listEditorViewModel = function () {
    // ... leave the rest as before ...
    this.selectedItems = ko.observableArray([]); // Initially select nothing
};

Now you can read selectedItems to see what items are selected, and if you write a value to that observable, it will change what’s selected in the UI.

To let the user remove their selected items, add a button and bind clicks on it to a method on the view model:

<button data-bind="click: removeSelected">
    Remove selected items
</button>
var listEditorViewModel = function () {
    // ... leave the rest as before ...
 
    this.removeSelected = function () {
        this.allItems.removeAll(this.selectedItems());
        this.selectedItems([]); // Reset selection to an empty set
    }
};

That’s great – now the user can remove one or more items from the list. But it doesn’t make sense for them to click “Remove selected items” if they haven’t got anything selected. Let’s make the button enabled only when at least one item is selected:

<button data-bind="click: removeSelected, enable: selectedItems().length > 0">
    Remove selected items
</button>

Easy! You can use arbitrary JavaScript expressions in bindings. If your bindings reference one or more observables, they’ll be re-evaluated automatically any time those observables change. So now the “Remove” button becomes enabled or disabled depending on whether anything is selected.

image3

What if you wanted to let the user sort the items into alphabetical order? Again, you could do this by adding a method to the view model and binding a new button to that method. Alternatively – just to show you that you can use function literals in bindings – here’s a standalone way to do it:

<button data-bind="click: function() { allItems.sort() }, enable: allItems().length > 1">
    Sort
</button>

I’ve made this button enable only when there are at least two items (it’s pointless to “sort” a single item). Notice that selection is retained, because we didn’t change selectedItems.

image4

That’s a fair bit of functionality in just a few lines of code. As I explained earlier, the benefit of Knockout and the MVVM pattern is that it scales very well in complexity – you don’t have to track how one part of the UI affects another; you just manipulate your view model and all affected parts of the UI change on their own. For example, in the preceding tutorial, removing items can make the ‘Sort’ button become disabled, but we didn’t have to write any explicit code in a ‘Remove’ click handler to make that happen.

To build on this knowledge, see the online demos of other examples (arranged in order of increasing sophistication) and look at their HTML source code to see how it’s done.

Requirements, Licensing, and Browser Support

Knockout is written in pure JavaScript, so it has no server-side requirements at all. Your web application can be written in ASP.NET MVC, PHP, Ruby on Rails – whatever.

The core of Knockout doesn’t depend on any other JavaScript library. However, the default template engine, jquery-tmpl, obviously depends on jQuery. If you don’t like that you can plug in another template engine, but I expect most people will be using jQuery anyway.

Regarding browser support, I’ve designed and tested it to work with IE 6 – 8, Firefox 2 – 3.6, and current versions of Chrome, Safari (verified on Windows and iPhone), and Opera. I fully expect it to work with older versions of Chrome, Safari, and Opera, but haven’t tried it – there’s only so much browser installation one person can bear… There’s a good set of automated specifications (BDD-style, written using JSSpec) so you can run these on any browser/platform to get a good sense of what features are working. Hopefully all of them :)

I’m releasing this project under the Ms-Pl license (an OSI-approved license). Some of my other code is licensed in the same way, so this keeps things simple for me, and it means you can use the library in any commercial or non-commercial project.

Where do I go from here?

For more details, examples, source, and downloads, see the project’s homepage at http://knockoutjs.com

jQuery Ajax uploader plugin (with progress bar!)

Javascript, MVC, UI, jQuery 88 Comments »

Do your web applications ever involve letting the user upload a file? If so, how’s the end-user experience: do you show a nice progress bar during the upload, or do you just leave the user waiting for minutes, with no clue when (if ever) the upload will complete?

Please show a progress bar, otherwise users will be justified in hating you. Check out this video to see one way it can work:


If you’re not seeing a video here, your feed reader is hiding it. View this post in a browser to see the video.

Those of you who attended my ASP.NET MVC talk at DDD7 last weekend might recognise this ;)

To create this behaviour, I implemented a simple jQuery plugin that replaces normal <input type=”file”/> elements with funky Ajaxy asynchronous uploader widgets. Behind the scenes, it uses the excellent SWFUpload library. All the clever stuff is in SWFUpload; all I did is set up the progress bar / cancellation behaviours, and make it easier to use if you’re already using jQuery.

Notice that it still works if the user doesn’t have JavaScript running in their browser. It gracefully degrades to “traditional” <input type=”file”/> behaviour. This is known as progressive enhancement or unobtrusive JavaScript.

Download

Here are all the files you need to accomplish this: Download jQuery-asyncUpload-0.1.js.

Setup instructions

Uploading files via Ajax, by nature, involves setting things up both on the server and on the client. The most reliable way to get this working successfully in your own app is to download the demo ASP.NET MVC project (see the end of this post) and copy the relevant aspects of its workings into your own app.

Nonetheless, here is an outline of the steps needed to get jQuery-asyncUpload-0.1.js working in your app, assuming you’ve already got jQuery in there:

1.  Add jQuery-asyncUpload-0.1.js, swfupload.js, and swfupload.swf to your project. In an ASP.NET MVC app, you might like to put these in /Scripts.

2.  Add script tags to reference the JavaScript files.

<head>
    <!-- Adjust the file paths as needed for your project -->
    <script src="/Scripts/jquery-1.2.6.min.js"></script>
    <script src="/Scripts/swfupload.js"></script>
    <script src="/Scripts/jquery-asyncUpload-0.1.js"></script>
</head>

3.  Add an old-style HTML file upload control to one of your pages:

<input type="file" id="yourID" name="yourID" />

4. Add a jQuery statement that replaces this file upload control with an asynchronous uploader when JavaScript is available:

<script>
    $(function() {
        $("#yourID").makeAsyncUploader({
            upload_url: "/Home/AsyncUpload", // Important! This isn't a directory, it's a HANDLER such as an ASP.NET MVC action method, or a PHP file, or a Classic ASP file, or an ASP.NET .ASHX handler. The handler should save the file to disk (or database).
            flash_url: '/Scripts/swfupload.swf',
            button_image_url: '/Scripts/blankButton.png'
        });
    });        
</script>

These options are explained later in this blog post. You must make sure to correctly reference the location of swfupload.swf, and put a button image wherever button_image_url specifies.

5. Add some CSS rules to style the progress bar. I’m using the following, though bear in mind it has some nasty hacks to make IE do an inline float properly. CSS gurus might structure this more cleanly.

DIV.ProgressBar { width: 100px; padding: 0; border: 1px solid black; margin-right: 1em; height:.75em; margin-left:1em; display:-moz-inline-stack; display:inline-block; zoom:1; *display:inline; }
DIV.ProgressBar DIV { background-color: Green; font-size: 1pt; height:100%; float:left; }
SPAN.asyncUploader OBJECT { position: relative; top: 5px; left: 10px; }

5. At this point, check you have something working. The visitor should now be able to select a file to upload, and should immediately get an alert box saying “Error 404” – that’s because you’ve configured the control to do an asynchronous upload to /Home/AsyncUpload, but your web app probably doesn’t have anything at that URL.

Also, if you use FireBug to inspect the DOM, you’ll see that your <input type=”file” /> has been dynamically replaced with the following:

<span class="asyncUploader">
   <div class="ProgressBar" style="display: none;"> 
	<!-- This is the progress bar itself - you can style it with CSS -->
   </div>
   <object type="application/x-shockwave-flash" ... >
       ... SWF config here ...
   </object>
   <input type="hidden" name="yourID_filename"/>
   <input type="hidden" name="yourID_guid"/>
</span>

Those two hidden inputs let you keep track of any file that was asynchronously uploaded.

6. Work on your web app so that it *does* handle file uploads to /Home/AsyncUpload (or whatever URL you’ve configured in step 4). The handler should save the uploaded file to disk, then return a unique token, such as a GUID or filename, to will identify the file you just uploaded. See the demo project for a simple way to do this using ASP.NET MVC.

7. When the containing form is finally submitted, check whether a file was sent with the request. This will happen if the user doesn’t have JavaScript enabled, as they’ll revert to traditional uploading behaviour. Also check for the hidden inputs called yourID_guid and yourID_filename – these will be populated if the visitor *does* have JavaScript enabled, and reflect any file that was uploaded asynchronously.

Further configuration

The asynchronous uploader plugin has plenty of properties you can configure in step 4 above:

Property Meaning Example
flash_url Location of swfupload.swf “/Scripts/swfupload.swf”
upload_url URL of the handler to which files will be asynchronously sent

Important: This is not the name of a directory or file on your server’s hard disk. It is the URL of a handler, such as an ASP.NET MVC action method, or a PHP page, or a classic ASP page, or an ASP.NET WebForms .ASHX handler, which will receive the file. It remains your job to implement such a handler and then save the incoming file to disk or database. For an example, see the ASP.NET MVC demo project at the end of this blog post.
“/Home/AsyncUpload”
file_size_limit Files above this size will be rejected before uploading even begins “3 MB”
file_types “Select files” popup will only show files of this type “*.jpg; *.gif”
file_types_description “Select files” popup will use this caption to describe the selectable file types “All images”
button_image_url Location of an image to be used for the “Choose file” button “blankButton.png”
button_image_width, button_image_height Dimensions of “Choose file” button 109
button_text Text that appears on the “Choose file” button "<font face=’Arial’ size=’13pt’>Choose file</font>"
disableDuringUpload Elements matching this jQuery selector will be disabled while an upload is in progress (useful to prevent form submission during async upload). “INPUT[type=’submit’]”
existingFilename Prepopulates the control with the name of a file already uploaded (useful when retaining state across multiple posts) “somefile.zip”
existingGuid Prepopulates the control with the arbitrary unique token you’ve given to a file already uploaded (useful when retaining state across multiple posts) “ec42555e-bfe7-45b0-87bf-36b1299f0398”
existingFileSize Prepopulates the control with the size, in bytes, of a file already uploaded (useful when retaining state across multiple posts) 548293
debug Turns on SWFUpload’s debugging console true

Demo project

The easiest way to understand all this is to check out a completed implementation. Here’s one written for ASP.NET MVC.

To compile and run this, you’ll need Visual Studio 2008 and ASP.NET MVC Beta. It saves asynchronously-uploaded files to the folder ~/App_Data/Files, giving each one a GUID as a filename. When you finally submit the form, it simply displays the filename and GUID of whatever file you uploaded. In a real app, you wouldn’t display the GUID to the end user, but would instead just use it to locate their file later.

kick it on DotNetKicks.com

Site Meter