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.