King_Nothing
King_Nothing

Reputation: 480

How do I force knockout to rebind a custom binding?

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

Upvotes: 3

Views: 8630

Answers (2)

Brian S
Brian S

Reputation: 1061

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.

Upvotes: 3

Mark Robinson
Mark Robinson

Reputation: 13278

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.

Upvotes: 2

Related Questions