Hello Jeff!
Well, one simpler way would be just to delay executing the rest of the code, wrapping it on another function, using the
Ext.createDelayed() function. Something like (not tested!):
var loadView = function (button, viewName, url) {
var panel = App.PnlCenter,
loader = panel.loader;
panel.clearContent();
var restOfFunction = function(button, viewName,url) {
var leftMenuButtons = App.LeftMenuPanel.query();
Ext.each(leftMenuButtons, function (button) {
button.el.setStyle('border-color', 'lightgrey');
});
button.el.setStyle('border-color', 'black');
loader.url = url;
loader.params = {
containerId: loader.target.getBody().id,
viewName: viewName
};
panel.load();
};
Ext.createDelayed(restOfFunction, 2000, this);
};
I'm not sure
clearContents()
should be running async tasks that would allow it to return before everything is in place, although every possibility must be taken. But one thing that may very well happen is:
- you call a direct method with a callback function that, for example, clears the contents.
- before the callback is actually called, you do something relying on the contents to be already cleared
Due to internet unstability, the callback may never be called in the end (lost packets, etc). Usually you'll hit an ajax timeout and an error dialog will be displayed -- when the call is to be totally lost. But the timeout is something between 10 and 30 seconds, enough time to not trigger any warning, yet run something before an ajax call returns with pre-requisites done.
But, in general, for a testing environment you should be good with the 2000ms wait (2 seconds) just to be sure you wait any overhead (even unexpected) to happen. Maybe also, as you are clicking repeatedly to reproduce the issue, your interval between clicks being quite fast, and being caught by garbage collection in-between, may then be the "timer bomb" to trigger the race condition.
You mentioned it happening after several clicks
here, just for reference.
You may set UI semaphores to avoid race conditions by, for example, if you click a button repeatedly to reproduce your issue, then make your method look like something like this:
var loadView = function (button, viewName, url) {
var panel = App.PnlCenter,
loader = panel.loader;
button.disable(); // Prevent the button to be clicked repeatedly!
panel.clearContent();
var leftMenuButtons = App.LeftMenuPanel.query();
Ext.each(leftMenuButtons, function (button) {
button.el.setStyle('border-color', 'lightgrey');
});
button.el.setStyle('border-color', 'black');
loader.url = url;
loader.params = {
containerId: loader.target.getBody().id,
viewName: viewName
};
loader.success = function () {
var button = App.myButton; // the scope might be different, there's a way to pass the current button, but left as exercise :)
button.enable();
}
// re-establish the button's clickability if the load process fails as well
loader.failure = function () {
var button = App.myButton;
// do something to ensure the whole page is not in a very inconsistent state -- if something was already changed and required the callback
// refreshing the whole page may be an option on such cases!
button.enable();
}
panel.load();
};