Long loads in durendal

I am trying to figure out where it is best to use a continuous load using Durandal.

From what I can tell, the general recommendation for loading data is in the ViewModel activate method, which I usually do - something like:

 viewModel.activate = function () { var loadPromise = myService.loadData(); return $.when(loadPromise).then(function (loadedData) { viewModel.data(data); }); }; 

I know that if I do not return the promise here, then there are usually binding problems - as this question and answer indicate .

However, executing the long-loading operation in the activate method makes the application "frozen" when the loading operation completes. For example, what if my download was now something like this?

 viewModel.activate = function () { // All loads return a promise var firstLoad = myService.loadFirstData(); var secondLoad = myService.loadSecondData(); var thirdLoad = myService.loadThirdDataWhichTakesAges(); return $.when(firstLoad, secondLoad, thirdLoad).then(function (one, two, three) { viewModel.one(one); viewModel.two(two); viewModel.three(three); }); }; 

In this case, the URL is updated to display the page being loaded, but the contents of the page still show the previous page (which I mean by “freezes”).

Ideally, it would be nice if the URL should change to a new page, and the page will display a new page (even if the data for this page has not yet been returned). Then, when each loading operation returns, the corresponding part of the page should be updated when the data is bound to the view model.

Is there a recommended way to achieve this inside Durandal?

My current solution is to start loading in the activate method, and then populate the data in the viewAttached method:

 var loadPromise; viewModel.activate = function () { // All loads return a promise var firstLoad = myService.loadFirstData(); var secondLoad = myService.loadSecondData(); var thirdLoad = myService.loadThirdDataWhichTakesAges(); loadPromise = $.when(firstLoad, secondLoad, thirdLoad); // Don't return the promise - let activation proceed. }; viewModel.viewAttached = function () { $.when(loadPromise).then(function (one, two, three) { viewModel.one(one); viewModel.two(two); viewModel.three(three); }); }; 

This seems to work, but I remember reading somewhere that relying on viewAttached not a good solution. I'm also not sure if there is a chance for the race condition, since I allow the action to be activated.

Any other recommendations?

+6
source share
3 answers

You do not need to return a promise, but in this case you should handle this in your knockout bindings so that you do not bind to undefined elements. You can try to get rid of this “return” when activated, but add a property indicating that the model is still loading. Something like that:

 viewModel.isLoading = ko.observable(false); viewModel.activate = function () { isLoading(true); var loadPromise = myService.loadData(); $.when(loadPromise).then(function (loadedData) { viewModel.data(data); isLoading(false); }); }; 

And then, in your opinion, you can have a section that appears when the view is still loading, and one that appears when loading. Sometinhg likes:

 <div data-bind:"visible: isLoading()">Loading Data....</div> <div data-bind:"visible: !isLoading()">Put your regular view with bindings here. Loading is done so bindings will work.</div> 
+8
source

What version of Durandal are you using? In Durandal 2.0.0pre, you will be allowed NOT to return a promise to activate so that the composition of the view (without data) can happen immediately.

You may consider refactoring viewModel.one etc. to a module that returns a constructor function, so that each, two, three will be responsible for obtaining its own data. This way you won’t have to wait for the first two calls to loadThirdDataWhichTakesAges . This would make sense in scenarios where one, two, three are not very dependent on each other.

0
source

For reference; I sent a similar question to the Durandal Google Group (actually asking if use uses activate and viewAttached in this way - OK idea) and got this answer from Rob Eisenberg:

That will probably work. The problem is that Knockout will destroy the data bindings on the elements if the properties are updated and the element is not currently contained in the document. This can happen depending on the time of the asynchronous code. Due to how the composition worked 1.x, this will cause problems if you do not return the promise from your activation function. It should work better in the Attached view, but depending on the nature of your composition, the view may be attached to its parent, but still not in the document. It depends on the depth of the composition. So you may run into problems with this if you have it in a deeply compiled module. Unfortunately, there is no clean way about this in Durandal 1.x due to knockout behavior. In Durandal 2.x, we redesigned the composition, so this problem is non-existent and returning the promise is no longer required (although you can still do it). Durandal 2.0 will be released in about two weeks.

0
source

Source: https://habr.com/ru/post/950596/


All Articles