Long running load operations in durandal - javascript

I'm trying to work out where the best place to run a long-running load operation is using Durandal.
From what I can tell, the general recommendation for loading data is in the ViewModel's activate method, which is what 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 don't return the promise here, then there's usually problems with the bindings - as this question and answer indicates.
However, executing a long running load operation in the activate method makes the app "freeze" while the load operation completes. For example, what if my load 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 scenario, the URL is updated to reflect the page which is being loaded, but the page content still shows the previous page (which is what I mean by "freezes").
Ideally, it would be good if the URL should change to the new page, and the page content should show the new page too (even though the data for that page has not yet been returned). Then, as each load operation returns, the relevant part of the page should be updated when the data is bound into the view model.
Is there a recommended way for achieving this inside Durandal?
My current solution is to kick-off the load 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);
});
};
It seems to work, but I remember reading somewhere that relying on viewAttached wasn't a good solution. I'm also not sure if there is potential for a race condition since I'm allowing the activate to proceed.
Any other recommendations?

You don't have to return a promise but in that case you must handle this in you knockout bindings so you woun't bind to elements that are undefined. You can try to get rid of that 'return' in activate but add a property indicating if model is still loading. Something like this:
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 view, you can have a section that shows up when view is still loading and one that shows up when loading is done. Sometinhg like:
<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>

Which version of Durandal are you using? In Durandal 2.0.0pre you would be allowed NOT returning a promise in activate so that the composition of the view (without data) could happen immediately.
You might consider refactoring viewModel.one etc. into a module that returns a constructor function, so that each one, two, three would be responsible for retrieving their own data. That way you first two calls wouldn't have to wait on loadThirdDataWhichTakesAges. That would make sense in scenarios where one, two, three are not heavily depend on each other.

For reference; I posted a similar question on the Durandal Google Group (effectively asking if using activate and viewAttached in this manner is an OK idea) and got this reply from Rob Eisenberg:
That will probably work. The problem is that Knockout will destroy
databindings on elements if the properties are updated and the element
isn't currently in the document. This can happen depending on the
timing of the async code. Because of the way composition worked in
1.x, this would cause problems if you didn't return the promise from your activate function. It should work better in viewAttached, 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 could encounter issues with this too if
you have this in a deeply composed module. Unfortunately, there isn't
a clean way about it in Durandal 1.x due to the knockout behavior. In
Durandal 2.x we have reworked composition so that this problem is
non-existent and returning the promise is no longer necessary (though
you can still do it). Durandal 2.0 will be releasing in about two
weeks.

Related

Overriding Core Drupal JS Function To Remove Behavior, Should I Edit Property, Or Leave Override Function Empty?

We have a use case where we need to block Drupal's core ajax error handling from alerting users (we're handling the error reporting on our own). Previously another developer had commented out a line in the core ajax.js file, to prevent Drupal from spawning the alert box, but I'd like to handle it without touching core.
From the core, drupal.js:
/**
* Displays a JavaScript error from an Ajax response when appropriate to do so.
*/
Drupal.displayAjaxError = function (message) {
// Skip displaying the message if the user deliberately aborted (for example,
// by reloading the page or navigating to a different page) while the Ajax
// request was still ongoing. See, for example, the discussion at
// http://stackoverflow.com/questions/699941/handle-ajax-error-when-a-user-
// clicks-refresh.
if (!Drupal.beforeUnloadCalled) {
alert(message);
}
};
My current fix, is to override the Drupal.displayAjaxError function and change the Drupal.beforeUnloadCalled property that determines whether or not to alert the error:
var ajax_error_backup = Drupal.displayAjaxError;
Drupal.displayAjaxError = function (message) {
Drupal.beforeUnloadCalled = true;
ajax_error_backup(message);
};
My question, is whether or not this is an appropriate fix? I know that I could also override the function and just leave it empty - costing fewer lines, and not invoking another call to the original function (and saving the object I've created by backing up the original in ajax_error_backup).
Am I adding complexity to keep things tidy, or should I just override with:
Drupal.displayAjaxError = function (message) {
//empty
};
To clarify - the desire is to never have this ajax alert occur, so there's not functional difference between my desire to keep things neat/tidy, and just overriding the function with a blank one - there isn't a case where want this alert to succeed.
Thanks in advance for helping this old dog think through something with fresh eyes.
In this case, there isn't one option that seems to be clearly better than the other. It should be handled on a case by case basis, and in this case, either of the methods really is adequate.
I personally opted for using the slightly more expensive method of overriding the function and calling it back, because I felt that it might be somewhat more future-proof:
var ajax_error_backup = Drupal.displayAjaxError;
Drupal.displayAjaxError = function (message) {
Drupal.beforeUnloadCalled = true;
ajax_error_backup(message);
};
If Drupal were to extend the function on their end in the future, there might be another condition that we wouldn't want to override.
Overriding with the empty function would be the cheapest, but would also potentially be a bit heavy handed.
It seems that either approach is valid, and is probably best handled case-by-case.

sapui5 Block View Rendering until model is loaded

I want to load a Model in my onInit Method, before the onBeforeRendering Method is called.
The problem withe attachRequestCompleted is that this called sometime after Rendering.
For example i get this error withe the ProcessFlow:
Render must not be called within Before or After Rendering Phase. Call ignored. - [object Object]
So my question is: Give it a function that block the view until the model ist loading?
I instantiated my Views over a manifes.json and my Models in the Component.js. So show Code is a bit difficult, but i load my Model like this:
var oModel = new JSONModel().attachRequestCompleted(function(){...});
var oConfigModel = new JSON().attachRequestCompleted(function(){
oModel.loadData(oConfigModel.getURL());
});
oConfigModel.loadData("config.json");
I do this because i formating and make some Models in dependency of my Main Model.
And Currently i put the data in the ProcessFlow over Databinding in the xml.
Blocking the UI never is a good idea! Esp. doing synchronous request as suggested in comments is aweful. Syncronous request are even deprecated on the main thread in major browsers.
You could set your view busy or even invisible until your model data is loaded like this:
onInit: function() {
var oView = this.getView();
oView.setBusy(true);
// option 2 set invisible: oView.setVisible(false);
... insert model init here ...
var oModel = ...
oModel.attachEventOnce("requestCompleted", function() {
oView.setBusy(false);
// option 2 set visible: oView.setVisible(true);
});
}
Note the use of attachEventOnce instead of attachRequestCompleted that will only execute - guess what - once.
Btw: Why is it so important to block or not show the UI at all? It is a much better experience for a user to already see sth. eventhough a view might be empty initially.
BR
Chris
An option here could be to use a busy indicator.
Start the indicator in your init function:
sap.ui.core.BusyIndicator.show();
...and stop the indicator in your attachRequestCompleted callback function:
sap.ui.core.BusyIndicator.hide();
More information here.

MeteorJS: Callback after template helper was updated

I'm new to Meteor.js, so hopefully this is an inability on my part rather than a limitation of the platform because it's pretty amazing otherwise.
What I'm trying to achieve is pretty straightforward: run Javascript whenever a template helper gets updated with new data (but not from the db!).
A simple example scenario could be this: A user makes a request to get some images. But rather than the images just "popping up", they should be hidden and fadein once they've been fully loaded (among other things like positioning them, etc.).
In other words, right after the helper receives new data, a function should run to do something with that data (that can not be done on the server before it is actually rendered).
If the data is from a collection, it's quite easy to achieve this with a subscribe callback.
However, there seems to be no callback for once a helper has rendered the new data.
Yes, it's possible to add a timeout of a few ms, but that's not a clean or reliable solution in my mind, because you obviously never know exactly how long it will need to render.
I've searched through dozens of seemingly related posts, but was not able to find anything that could be considered a "standard" way of achieving this...
Here's a bit of (simplified) example code to illustrate the scenario:
var images = [];
//When showImages is updated with new data from the images array...
Template.gallery.helpers({
showImages: function () {
return images;
}
});
//...this function should fire
function doMagicWork () {
...
}
//Because firing it on the on click event would be too soon,
//as the helper hasn't rendered yet
Template.gallery.events({
"click #fetch_images": function (event) {
Meteor.call("getImagesFromServer", function(error, result) {
images = result.content;
});
}
});
There is a pending feature for adding animation/transition support for UI changes (referenced here)
As an interim solution, you can use Blaze UI hooks. There are quite a few packages that use them. example here and here
In general, , Meteor way is to reduce the amount of boiler plate code. Smooth transition is something of a pattern rather than an individual thing for element and should be treated as such as per meteor philosophy.

Simplest approach to Node.js request serialisation

I've got the classic asynchronous/concurrency problem that folks writing a service in Node.js at some point stumble into. I have an object that fetches some data from an RDBM in response to a request, and emits a fin event (using an EventEmitter) when the row fetching is complete.
As you might expect, when the caller of the service makes several near-simultaneous calls to it, the rows are returned in an unpredictable order. The fin event is fired for rows that do not correspond to the calling function's understanding of the request that produced them.
Here's what I've got going on (simplified for relevance):
var mdl = require('model.js');
dispatchGet: function(req, res, sec, params) {
var guid = umc.genGUID(36);
mdl.init(this.modelMap[sec], guid);
// mdl.load() creates returns a 'new events.EventEmitter()'
mdl.load(...).once('fin',
function() {
res.write(...);
res.end();
});
}
A simple test shows that the mdl.guid often does not correspond to the guid.
I would have thought that creating a new events.EventEmitter() inside the mdl.load() function would fix this problem by creating a discrete EventEmitter for every request, but evidently that is not the case; I suppose the same rules of object persistence apply to it as to any other object, irrespective of new.
I'm a C programmer by background: I can certainly come up with my own scheme for associating these replies with their requests, using some circular queue or hashing scheme. However, I am guessing this problem has already been solved many times over. My research has revealed many opinions on how to best handle this--various kinds of queuing implementations, Futures, etc.
What I'm wondering is, what's the simplest possible approach to good asynchronous flow control here? I don't want to get knee-deep in some dependency's massive paradigm shift if I don't have to. Is there a relatively simple, canonical, definitive solution, and/or widespread consensus on which third-party module is best?
Could it be that your model.js looks something like this?
module.exports = {
init : function(model, guid) {
this.guid = guid;
...
}
};
You have to be aware that the object you're passing to module.exports there is a shared object, in the sense that every other module that runs require("model.js") it will receive a reference to the same object.
So every time you run mdl.init(), the guid property of that object is changed, which would explain your comment that "...a simple test shows that the mdl.guid often does not correspond to the guid".
It really depends on your exact implementation, but I think you'd want to use a class instead:
// model.js
var Mdl = function(model, guid) {
this.guid = guid;
};
Mdl.prototype.load = function() {
// instantiate and return a new EventEmitter.
};
module.exports = Mdl;
// app.js
var Mdl = require('model.js');
...
var mdl = new Mdl(this.modelMap[sec], guid);
mdl.load(...)

Watch for a property creation event?

I need to be able to determine when an object is created (not a DOM element -- a JavaScript object).
An answer to this question has some very useful looking code for creating observable properties, so you can have a function fire when a property changes.
In my situation I need to do something when the object/property is created, not an existing property changed, and my limited understanding of such matters did not help me figure out if or how I could use that code to do this after much squinting.
The situation is: page loads a bunch of scripts. Some of the scripts create things that are needed by other scripts, e.g:
ThisStuff = (function () {
// blah blah
return self;
} ());
Some other code needs to initialize this ThisStuff, whenever it's available, which may be after the DOM is done loading. The user doesn't actually need ThisStuff right away, so it's fine for it to happen whenever the script is done loading. So I would like to do something along lines of:
$(document).ready(function() {
wheneverIsAvailable(window,'ThisStuff', function(object) {
object.init(args);
})
});
I realize there are other solutions to this problem (changing script order, or loading scripts on demand) but those are difficult because of the architecture. So I'm only interested in a way to do this versus other solutions. If jQuery offers some such functionality, that's fine also as I'm using it.
You could have a setInterval checking a number of times a second to watch the specific variable. You can check whether it is created using obj.hasOwnProperty(prop). When it is created, you invoke the function, and clear the interval.
It might be dirty but it might also just work fine for you.
Edit: I coded this for you: http://jsfiddle.net/jhXJ2/2/. It also supports passing additional arguments to the function.
window.__intervals = [];
function wheneverIsAvailable(obj, prop, func) {
var id = (Math.random()+"").substring(2);
var args = arguments;
window.__intervals[id] = window.setInterval(function() {
if(obj.hasOwnProperty(prop)) {
window.clearInterval(window.__intervals[id]);
func(Array.prototype.slice.call(args, 3));
// Call function with additional parameters passed
// after func (from index 3 and on)
}
}, 1000/ 50);
}
wheneverIsAvailable(window, 'test', function() {
alert(arguments[0]);
}, 'Woot!');
window.setTimeout('window.test = 123', 1000);
This is a bit far-fetched but it might work.
You would need to use knockoutjs, a javascript library. It's awesome but is built for a slightly different purpose.
Anyways it has a dependentObservable thing which allows to fire up an event whenever a certain value changes. Now I know you want on creation but you can check whether your variable holds any value (other than what you provided initially), if yes then consider it initialize.
Let me know if you think this sounds feasible.

Categories