PDA

View Full Version : Take Control of your lagging mask.



hendricd
16 Aug 2007, 10:56 AM
Setting a loadMask (true||{msg: 'Loading...'}) on the grid (and other widgets) hooks the onbeforeLoad Event of the attached datastore to the loadMask. But, the datastore load-processing can be so intensive that the expected DOM update for the mask may not be visible until after the datastore.[re]load operation completes. Kinda defeats the purpose of the mask?

Here's how to smooth things out a bit:



// Let's add a couple new convenience methods to Ext.LoadMask
Ext.apply(Ext.LoadMask.prototype,{
visible:false,
onBeforeLoad : function(){
if(!this.disabled && !this.visible){
this.el.mask(this.msg, this.msgCls);
this.visible = true;
}
},
onLoad : function(){
this.el.unmask(this.removeMask);
this.visible = false;
},
show:function(msg, append){
if(!this.disabled){
if(msg){
this.msg= append?this.msg + '<br/>'+ msg:msg;
}
this.onBeforeLoad();
}
},
showDefer:function(msg,fn,config){
config || (config={});
this.show(msg, config.append||false);
if(fn){
config = Ext.apply({scope:this,millis:100,"arguments":[],appendArguments:false},config);
fn.defer(config.millis,config.scope,[].concat(config.arguments),config.appendArguments);
}
},
hide:function(){ this.onLoad(); }
});Now the example:




<style type="text/css">
html, body {
font:normal 12px verdana;
margin:0px;
padding:0px;
border:0px none;
overflow:hidden;
height:100%;
}
</style>
<script language="JavaScript" type="text/javascript">
var App = function(){

return {
startMask:null,
init: function(){
this.cm = new Ext.grid.ColumnModel(yourColumns);
this.ds = new Ext.data.Store(yourOptions);
this.grid = new Ext.grid.Grid('your-grid-container', {
ds: this.ds,
cm: this.cm,
loadMask: {msg: 'Loading...'}
});

this.grid.render(); //this is what hooks the loadMask to datastore

if(this.startMask){
this.startMask.hide(); //enuff candy
}

this.grid.loadMask.show(); //force it 'on' now

var options = {callback:function(r, options, success){
if(success){App.grid.getSelectionModel().selectFirstRow();}
// .... do other stuff

}
};

//Give the DOM a chance to show your loadMask: defer the load for a few milliseconds !
this.ds.load.defer(100,this.ds,[options]);

//then, the datastore.load method will clean-up the mask, as usual, for you.
}
};
}(); //end App

Ext.onReady(function(){

// First, a generic document mask (candy) when the DOM is ready:
App.startMask = new Ext.LoadMask(document.body,{});

//the easy way
App.startMask.showDefer('Setting Up Your Grid...',App.init,{scope:App, millis:600});

// or, the classic way
//App.startMask.show('Setting Up Your Grid...');
//App.init.defer(600,App); //Give the startMask time to show itself.

}, App, true);
</script>
[edit] Added showDefer method to handle a defered call at the same time.
[tags: loadmask mask lagging]
Cheers,

Mark
16 Aug 2007, 11:47 PM
Hi Doug, I ' ve no clue what the dots in the line

var self = this, options = {..., stand for ?
Could you give me an example please?

Thanks in advance!

Mark

hendricd
17 Aug 2007, 5:34 AM
@Mark - .... simply means other options you may want to include. You can remove them (or the options altogether) if you just want to try the approach.

Mark
17 Aug 2007, 5:48 PM
Hi Doug, thanks for the response.
Now I've got my example to run, but I'm not sure if it shows the expected effect, because I miss the the startmask.

Would you be so kind and take a look to the code or my working example (http://ext.auragard.de/test/loadMask.html)I hope you can give me a hint to what I' ve done wrong.:-/

Mark


var App = function(){
return {
init: function(){
// First, a generic document mask (candy):
var startMask = new Ext.LoadMask(document.body,{msg:'Setting Up...',msgCls:'ext-el-mask-msg x-mask-loading',removeMask:false});
startMask.show('Your Grid first...',true);

this.ds = new Ext.data.Store({
proxy: new Ext.data.ScriptTagProxy({
url: 'http://ext.auragard.de/proxygetdata.php'
}),
reader: new Ext.data.JsonReader({
root: 'results',
totalProperty: 'totalCount',
id: 'id'
}, [
{name: 'id',type:'int'},
{name: 'Name',mapping: 'Name'},
{name: 'HomePhone'},
{name: 'WorkPhone'},
{name: 'EmailAddress'},
{name: 'StreetAddress'},
{name: 'Zipcode'},
{name: 'City'}
])
, remoteSort: true
});
// the data store
this.cm = new Ext.grid.ColumnModel([{
id: 'results',
header: "ID",
dataIndex: 'id',
width: 35

},{
header: "Name",
dataIndex: 'Name',
width: 100,
hidden: false
},{
header: "HomePhone",
dataIndex: 'HomePhone',
width: 100,
css: 'white-space:normal;'

},{
header: "WorkPhone",
dataIndex: 'WorkPhone',
width: 100,
css: 'white-space:normal;'

},{
header: "EmailAddress",
dataIndex: 'EmailAddress',
width: 150,
css: 'white-space:normal;'

},{
header: "StreetAddress",
dataIndex: 'StreetAddress',
width: 200,

css: 'white-space:normal;'

},{
header: "Zipcode",
dataIndex: 'Zipcode',
width: 80,

css: 'white-space:normal;'

},{
header: "City",
dataIndex: 'City',
width: 150,
css: 'white-space:normal;'

}]);

this.grid = new Ext.grid.Grid('listView', {
ds: this.ds,
cm: this.cm,
loadMask: {msg: 'Loading...'}
});
this.layout = Ext.BorderLayout.create({
center: {
margins:{left:3,top:3,right:3,bottom:3},
panels: [new Ext.GridPanel(this.grid)]
}
}, 'grid-panel');

this.grid.render(); //this is what hooks the loadMask to datastore
startMask.hide(); //enuff candy

this.grid.loadMask.show(); //force it 'on' now


var self = this,options = {callback:function(r, options, success){
if(success){self.grid.getSelectionModel().selectFirstRow();}
// .... do other stuff

}
};

//Give the DOM a chance to show your loadMask: defer the load for a few milliseconds !
this.ds.load.defer(6000,this.ds,[options]);

//then, the datastore.onload event will clean-up the mask, as usual, for you.
}
};
}(); //end App

Ext.onReady(App.init, App, true);

hendricd
18 Aug 2007, 8:27 AM
@Mark - Sorry the initial example (startMask candy) also suffers from the same problem I describe early in the thread. See the revised example on how to handle that. Your grid with enhanced gridMasking looks cleaner/smoother though, doesn't it ?

Mark
18 Aug 2007, 9:14 AM
Yes, it does, indeed!:D
Thank you, Dough, for the improvement!

Greets,
Mark

hendricd
29 Aug 2007, 12:53 PM
features and revised the example to demonstrate.

violinista
29 Aug 2007, 1:45 PM
Thanks for the great widget...

Have you considered adding this loadMask into grid prototype, for handling multiple loading (for example, in paging grid or when reloading grid's dataset)? It will great improve functionality, and also will help to automatically get this mask with all new grid instances.

Regards, violinista

hendricd
30 Aug 2007, 10:35 AM
@violinista - I would resist that notion, as this can be used just about anywhere. The goal here is to compensate for the 'various' browsers poor DOM refresh rates. This way you are in complete control of masking for ANY block-widget/parent (not just wrapping AJAX calls).

Here's a masking Tree example:


var Tree = Ext.tree;
var testTree = new Tree.TreePanel('treePanel', {
animate:false,
enableDD:false,
containerScroll: true,
dropConfig: {appendOnly:true}});
var loader = new Tree.TreeLoader({dataUrl:'getNodes.php',requestMethod : "GET"}));
var treeRoot = new Tree.AsyncTreeNode({
text: 'Nodes',
expanded:false,
loader: loader,
draggable:false
});

var maskHost = testTree.el; //or other relevant block parent

Ext.apply(loader,{fullMask : new Ext.LoadMask(maskHost,{msg:'Gathering Nodes, Please Wait...'}) });
loader.fullMask.removeMask=false;

loader.on({ 'load' : function(){this.fullMask.hide();}
,'loadexception' : function(){this.fullMask.hide();}
,'beforeload' : function(){this.fullMask.show();}
,scope : loader
});

testTree.setRootNode(treeRoot);
treeRoot.expand(false, false);

gkassyou
11 Sep 2007, 7:51 AM
how can I apply this to multiple nested store loads?

hendricd
11 Sep 2007, 8:57 AM
how can I apply this to multiple nested store loads?

See response to this inquiry here (http://extjs.com/forum/showthread.php?p=62235#post62235).

gkassyou
11 Sep 2007, 9:59 AM
Thx, I will give it a try and post back.

gkassyou
12 Sep 2007, 5:58 AM
It's working. Thanks for your help hendricd