Durante o desenvolvimento dos meus sistemas me deparei com um grande problema ao apresentar ao usuário final telas em forma de formulários que continham um ou mais Stores relacionados, em forma de ComboBox, Grid, etc. Prefiro carregar todos os dados a serem apresentados na tela em sua criação, não gosto muito do estilo “clicar no ComboBox e esperar carregar”, por motivos que incluem a apresentação dos dados, exemplo:
O usuário abre um Grid de funcionários, clica no botão de editar o qual abre uma tela contendo um formulário onde os dados do Grid serão carregados para os campos. Se os ComboBox não estiverem carregados no momento do loadRecord aparecera apenas os códigos nestes campos, por isso precisamos garantir que todos os Stores dos ComboBox estejam carregados antes de popularmos o formulário. Ao ter 10 ComboBox como controlar quando todos terminaram suas requisições para que possamos enfim efetuar um loadRecord? Com o Ext.ux.StoreGroup.
Que diabos é o Ext.ux.StoreGroup?
Ext.ux.StoreGroup é um componente não visual herdado do Ext.util.MixedCollection que serve como uma lista de Stores, adicionamos nossos Stores secundários a ele, chamamos o método loadAll que irá disparar o método load de todos os Stores adicionados a ele e por fim irá disparar o evento afterLoad quando todos os Stores terminarem de carregar seus dados onde podemos chamar o método LoadRecord para carregar os dados ao nosso formulário.
Ext.ux.StoreGroup:
Ext.namespace('Ext.ux');
Ext.ux.StoreGroup = function(){
this.addEvents('afterLoad');
Ext.ux.StoreGroup.superclass.constructor.call(this);
};
Ext.ux.StoreGroup = Ext.extend(Ext.util.MixedCollection, {
inLoading: 0,
maskEl: null,
maskText: 'Carregando...',
maskCls: 'x-mask-loading',
loadAllFired: false,
register: function(){
for(var i = 0, s; s = arguments[i]; i++){
s.on('beforeload', this.onBeforeLoad, this);
s.on('load', this.onLoad, this, false);
s.on('loadexception', this.onLoad, this, true);
this.add(s);
}
},
unregister: function(){
for(var i = 0, s; s = arguments[i]; i++){
s.un('beforeload', this.onBeforeLoad, this);
s.un('load', this.onLoad, this, false);
s.un('loadexception', this.onLoad, this, true);
this.remove(this.lookup(s));
}
},
lookup: function(id){
return typeof id == "object" ? id : this.get(id);
},
getKey: function(o){
return o.storeId || o.id;
},
onBeforeLoad: function(){
this.inLoading += 1;
},
onLoad: function(){
this.inLoading -= 1;
if((this.inLoading == 0)&&(this.loadAllFired)){
this.fireEvent('afterLoad');
if(this.mask){
this.mask.hide();
}
this.loadAllFired = false;
}
},
loadAll: function(obj){
Ext.apply(this,obj);
if(this.maskEl){
if(!this.mask){
this.mask = new Ext.LoadMask(this.maskEl);
}
Ext.apply(this.mask, {msg:this.maskText, msgCls:this.maskCls})
this.mask.show()
}
this.loadAllFired = true;
this.inLoading = 0;
if(this.getCount() == 0){
this.fireEvent('afterLoad');
this.loadAllFired = false;
}
this.each(function(i){
i.load();
},this)
}
});
Pequeno Override no Store pra facilitar a vida:
Ext.override(Ext.data.Store, {
constructor: Ext.data.Store.prototype.constructor.createSequence(function(c){
if(this.storeGroup){
this.storeGroup.register(this);
}
})
})
Exemplo de formulário usando os caras acima:
Destacado abaixo as duas formas de se adicionar um Store ao StoreGroup, lembrando que a primeira maneira requer o override acime, a segunda maneira é nativa ao componente.
Ext.onReady(function(){
Ext.form.Field.prototype.msgTarget = 'side';
Ext.form.FormPanel.prototype.bodyStyle = 'padding:5px';
Ext.form.FormPanel.prototype.labelAlign = 'right';
Ext.QuickTips.init();
var sg = new Ext.ux.StoreGroup();
var dsProfissao = new Ext.data.JsonStore({
url:'dados.php',
storeGroup: sg, //Usando override no Store.
baseParams:{
action:'profissao'
},
fields:[
{name:'id', type:'int'},
{name:'profissao'}
]
})
var dsCidade = new Ext.data.JsonStore({
url:'dados.php',
baseParams:{
action:'cidade'
},
fields:[
{name:'id', type:'int'},
{name:'cidade'}
]
})
var dsSexo = new Ext.data.JsonStore({
url:'dados.php',
baseParams:{
action:'sexo'
},
fields:[
{name:'id', type:'int'},
{name:'sexo'}
]
})
//Método tradicional
sg.register(dsCidade,dsSexo);
var win = new Ext.Window({
height: 210,
width: 620,
layout: 'fit',
title: 'Ext.ux.StoreGroup',
items:[{
xtype: 'form',
labelWidth: 70,
defaults:{
width:500
},
items: [{
xtype: 'textfield',
fieldLabel: 'Nome',
name: 'nome',
allowBlank: false
},{
xtype: 'textfield',
fieldLabel: 'Sobrenome',
name: 'sobrenome',
allowBlank: false
},{
xtype: 'combo',
fieldLabel: 'Profissão',
store: dsProfissao,
valueField: 'id',
displayField: 'profissao',
name: 'profissao',
mode: 'local',
triggerAction: 'all'
},{
xtype: 'combo',
fieldLabel: 'Cidade',
store: dsCidade,
valueField: 'id',
displayField: 'cidade',
name: 'cidade',
mode: 'local',
triggerAction: 'all'
},{
xtype: 'combo',
fieldLabel: 'Sexo',
store: dsSexo,
valueField: 'id',
displayField: 'sexo',
name: 'sexo',
mode: 'local',
triggerAction: 'all'
}]
}],
buttons:[{
text:'Salvar'
},{
text:'Cancelar'
}]
})
win.on('show', function(c){
sg.loadAll({maskEl:c.body, maskText:'Carregando Dependências...'});
})
sg.on('afterLoad', function(){
win.items.items[0].getForm().loadRecord({
data:{
profissao:1,
cidade:2,
sexo:1,
nome:'Rodrigo',
sobrenome:'Nascimento'
}
});
})
win.show();
})
Exemplo
Twittar Isto!

Mais um importantissimo post, Valew Rodrigo…… Continue assim
Abraço.
Cara, show d++++++++++++++++++++. O que esta encorporando em vc? rsrsrsrs. Parabéns mesmo por mais esse post. Ajudará varias pessoas, começando comigo. Heheheheh. Vlwsssssss
Cara muito bom esse componente, vai ser bem util pra min em alguns casos…
cara mais um elogio, estava aqui passando raiva com meus combos, e depois de quebrar a cabeça , lembrei que que vc criou essa ux, simplismente resolveu meu problema. Vlw mais uma vez Rodrigo.
hehehe, vlw kra, é bom ser lembrado nos momentos de panico hehe
Abraços
poderia atualizar este exemplo para o Ext JS 4.x?
eu tentei mas estou com problemas..
agradeço a ajuda..
No momento não tenho tempo. No ExtJS 4 existe a definição de dependencias entre Models, talves não seja necessária a atualização deste meu ux.
Abraços