3

I would like to know how I can force a knockout binding to refresh it's value. Normally we use an observable and that way the binding can happen automatically when the observable changes. But in my case I have created a custom binding:

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

        parameters.concat([function (data) {
            $(element).html('Unable to retrieve html.');
        } ]);
        value.source.apply(null, parameters);
    }
}
}

This is so that a function which performs an asynchronous JSON call can update the respective element (with the returned HTML) once the call completes. The element, a DIV in this case, looks like this:

<div id="myDiv" data-bind="asyncHtml: {source: getHtml, params: [myId()]}">

My problem is that, another feature on this page can change database values that require myDiv to be updated as a result. I can probably find a complicated way to correct this problem but I was wondering if there was a simpler way where I can just force the binding to reapply?

NOTE: getHtml is a function on my viewmodel which performs the JSON call to retrieve the HTML.

Thanks

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
King_Nothing
  • 480
  • 1
  • 5
  • 15

2 Answers2

3

I hope I understood what you are trying to accomplish correctly, but I am not sure, so let me explain how I understand your objective.

  1. You have a div (#myDiv) which will retrieve it's initial HTML from the server.
  2. You have an ajax function (getHtml) which retrieves this html and onSuccess updates #myDiv, possibly with this:

    $('#myDiv').html(serverResponseHTMLContent);

  3. You then have another function which may produce different HTML that should take the place of the server generated html.

If this is all correct then I would suggest you use knockout's html binding.

Your div would look like so.

<div id="myDiv" data-bind="html: myDivInnerHtml">

myDivInnerHtml would be part of your viewModel and should be an observable as you say you usually do. Before the initial bind, call getHtml and have it set the value for myDivInnerHtml instead of actually setting the html for myDiv.

myDivInnerHtml = ko.observable(serverHtmlString);

Then when you apply the binding, myDiv's inner Html will be set by knockout. To update the html, your client side function can change the value of myDivInnerHtml.

myDivInnerHtml(clientSideFunctionHtmlString);

If my assumptions are wrong and you have recreate the same html with different value, then you should use a template if possible and the server should not be sending the html, but instead the values to bind to the html.

Also, if the client side function is not creating html, but instead values to be bound to the html, then this will also not work.

Brian S
  • 1,051
  • 9
  • 10
  • Thanks for your input, the HTML would be different in the sense that some values have changed in a database subsequent to the loading of the html and so I wanted to "refresh" the html. I will see if I can find a way to make use of an observable to store the html as you suggested. Thanks. – King_Nothing Jun 20 '12 at 10:52
  • Thanks for the suggestion. I ended up creating an observable for the html. Then in the success handler for the asynchronous JSON call I set the value of the observable. Problem solved :) Thanks! – King_Nothing Jun 20 '12 at 12:21
2

You could look at the valueHasMutated() function which notifies subscribers that they should re-evaluate the observable.

See How to force a view refresh without having it trigger automatically from an observable? for a bit more explanation.

Community
  • 1
  • 1
Mark Robinson
  • 13,128
  • 13
  • 63
  • 81
  • Thanks for your suggestion, but getHtml is a function and not an observable. I'll see if I can find a way to use valueHasMutated and an observable to get it to work. – King_Nothing Jun 15 '12 at 12:21
  • 1
    Shot in the dark but if getHtml is a function that gets JSON you take a look at this post http://www.knockmeout.net/2011/06/lazy-loading-observable-in-knockoutjs.html - I've only skim read it but it deals with lazy loading JSON data so may help. – Mark Robinson Jun 15 '12 at 12:30
  • Thanks for the lazy loading link, it was useful. I ended up using a solution based on Brian's answer above. – King_Nothing Jun 20 '12 at 12:22