Loading MVC PartialViews asynchronously using KnockoutJS

This question on StackOverflow asks (indirectly) how to use KnockoutJS to asynchronously load the result of a PartialView call into a div using jQuery.ajax.

The poster’s original attempt specified a getHtml functionon the view model, and then used the html binding to set the getHtml function. Unfortunately this cannot work as getHtml makes an asynchronous call to the server and so cannot return a value for the knockout binding to use.

One way (of many) that you could work around this would be to create a custom binding as demonstrated here.

This works by taking 2 parameters to the asyncHtml: a function to call that takes a success callback as its final parameter (plus any other parameters) and an array of the parameters that need to be passed to that function.

<div data-bind="asyncHtml: { source: getHtml, params: [123, 456] }"></div>

The custom binding then grabs these values, concats a custom callback onto the parameters that are passed to it, and calls the specified function:

ko.bindingHandlers.asyncHtml = {
    init: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var parameters = value.params.concat([function(data) {
           $(element).html(data); 
        }]);
        value.source.apply(null, parameters);
    }
};

Finally we can re-implement our view model HTML-retrieving method to make the POST call and invoke the new success handler:

var ViewModel = function() {
    this.getHtml = function(param1, param2, callback) {
        $.ajax(
            {
                type: "POST",
                url: "/echo/html/",
                data: {
                        html: "<p>server response " + param1 + " " + param2 + "</p>",
                        delay: 1
                    },
                success: callback,
                dataType: "text"
            });            
    };
};

This approach means we can flexibly call any method on our view model that wants to make an async call and then insert the result back into the view.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s