Refresh / Re-apply data-bindings from knockout when viewmodel changes

5,241 views
Skip to first unread message

Jone Polvora

unread,
Feb 10, 2013, 8:23:01 PM2/10/13
to duran...@googlegroups.com
I'm new to durandal/javascript, I'm from silverlight/wpf/caliburn-micro world. So maybe this is a newbie question, sorry...

In my viewmodel, I have a kind of "complex" property, called "model", that is initialized with a null value. In the viewmodel activate() function, I call some web service and when the results came, I set the model with the value from webservice. The view has bindings to the model property, like model.Id, model.Description, etc. After I set the model value with the new value from web service, the view doesn't reflect the changes of the model property. I need to tell to knockout "refresh" the databindings. Is this possible? I know I can create several observables properties, and set values manually, but I'm looking for a easier way.

Rob Eisenberg

unread,
Feb 10, 2013, 8:34:42 PM2/10/13
to Jone Polvora, duran...@googlegroups.com
You should return a promise from your activate function, so that Durandal knows that you are doing something asynchronous. Have a look at the starter template's flickr module for an example.


On Sun, Feb 10, 2013 at 8:23 PM, Jone Polvora <jpol...@gmail.com> wrote:
I'm new to durandal/javascript, I'm from silverlight/wpf/caliburn-micro world. So maybe this is a newbie question, sorry...

In my viewmodel, I have a kind of "complex" property, called "model", that is initialized with a null value. In the viewmodel activate() function, I call some web service and when the results came, I set the model with the value from webservice. The view has bindings to the model property, like model.Id, model.Description, etc. After I set the model value with the new value from web service, the view doesn't reflect the changes of the model property. I need to tell to knockout "refresh" the databindings. Is this possible? I know I can create several observables properties, and set values manually, but I'm looking for a easier way.

--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project

Jone Polvora

unread,
Feb 10, 2013, 9:09:00 PM2/10/13
to duran...@googlegroups.com, Jone Polvora, r...@bluespire.com
It works! Thank you very much for the quick response. I can presume now that the data-binding stuff is done after viewmodel.activate() returns, right?

Rob Eisenberg

unread,
Feb 10, 2013, 9:15:46 PM2/10/13
to Jone Polvora, duran...@googlegroups.com
Yes. That is correct. Here's a brief explanation:

Your query is async. If we don't wait to databind, knockout can get confused...especially if the observable is updated when we are in the middle of the binding process. By returning a promise from activate, you can basic tell Durandal to wait until your async code is complete. This works nicely if you are using the router (and a view based on the shell from the template) because it will show the spinner and wait to animate the new page in as well.

Daniel Walton

unread,
Feb 11, 2013, 9:17:11 AM2/11/13
to duran...@googlegroups.com, Jone Polvora, r...@bluespire.com
I am having a similar issue with activate() in my dev environment. Often the HTTP response comes back too quickly such that the bindings do not update afterward. It almost seems like knockout is still busy when it returns. If I put in a 100ms delay in my JSON service, the problem disappears. I really don't like that solution :). Is there a better asynchronous pattern I could use to ensure that the bindings will always update?

Rob Eisenberg

unread,
Feb 11, 2013, 9:18:42 AM2/11/13
to Daniel Walton, duran...@googlegroups.com, Jone Polvora
Use activate, as described above.

Daniel Walton

unread,
Feb 11, 2013, 10:02:20 AM2/11/13
to duran...@googlegroups.com, Daniel Walton, Jone Polvora, r...@bluespire.com
My bad.. I was missing the return keyword in my activate() function.

Jone Polvora

unread,
Mar 11, 2013, 2:45:37 AM3/11/13
to duran...@googlegroups.com
Just sharing some tips... If my viewmodel implements the "Revealing Prototype Pattern", even if I'm returning a promise from activate function, the binding will not works.
So in this case I must return a ko.computed observable that wraps my entity.

define(['services/dataService'], function (DataService) {
var ViewModel = function () {
//...
}
ViewModel.prototype = function () {
//
var dataservice = new DataService('api/todo');
var entity = ko.observable();
return {
activate: function(data) {
//async operation
dataservice.get("Todo", data.splat[0]).then(function(result){ 
entity(result); 
}); 
},
model: ko.computed(function(){
return entity();
}),
}
}();
 
return new ViewModel();
});

<div>
<input type="text" data-bind="model().Description" />
</div>

This works fine. Anytime my entity changes, the computedObservable will update the bindings.
Reply all
Reply to author
Forward
0 new messages