Ext.ux.StoreGroup – Carregando Dependências

Ext.ux.StoreGroup – Carregando Dependências

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!

Quem escreve

Rodrigo Krummenauer do Nascimento, técnico em informática, cursando Sistemas de Informação na FACCAT, nascido em 20/07/1988, 3 anos de experiencia profissional em Delphi com PostgreSQL, 2 anos de experiencia profissional em ExtJS com PHP, moderador do fórum nacional de ExtJS, singelo morador de uma pacata cidade de interior no Rio Grande do Sul, coordenador e desenvolvedor de um grupo de P&D em sua faculdade, http://nti.faccat.br.