ExtJS 4: Criando Menus Accordion Dinamicamente usando MVC e Associação de Models

No post de hoje vamos ver como criar um menu dinâmico usando panel com layout accordion e dentro de cada panel um tree panel com as opções.

Esse post aborda a arquitetura MVC e também associação de Models.

Criando os Models

MenuRoot

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]Ext.define('Sencha.model.MenuRoot', {
extend: 'Ext.data.Model',

uses: [
'Sencha.model.MenuItem'
],

idProperty: 'id',

fields: [
{
name: 'title'
},
{
name: 'iconCls'
},
{
name: 'id'
}
],

hasMany: {
model: 'Sencha.model.MenuItem',
foreignKey: 'menu_id',
name: 'items'
}
});[/code]

MenuItem

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]Ext.define('Sencha.model.MenuItem', {
extend: 'Ext.data.Model',

uses: [
'Sencha.model.MenuRoot'
],

idProperty: 'id',

fields: [
{
name: 'text'
},
{
name: 'iconCls'
},
{
name: 'className'
},
{
name: 'id'
},
{
name: 'menu_id'
}
],

belongsTo: {
model: 'Sencha.model.MenuRoot',
foreignKey: 'menu_id'
}
});[/code]

Criando a Store

Menu

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]Ext.define('Sencha.store.Menu', {
extend: 'Ext.data.Store',

requires: [
'Sencha.model.MenuRoot'
],

constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
storeId: 'MenuStore',
model: 'Sencha.model.MenuRoot',
proxy: {
type: 'ajax',
url: 'data/menu.json',
reader: {
type: 'json',
root: 'items'
}
}
}, cfg)]);
}
});[/code]

Json Carregado - exemplo

Criando as Views

Menu

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]Ext.define('Sencha.view.Menu', {
extend: 'Ext.panel.Panel',
alias: 'widget.menu',

height: 432,
width: 251,
layout: {
type: 'accordion'
},
iconCls: 'home',
title: 'Menu',

initComponent: function() {
var me = this;

me.callParent(arguments);
}

});[/code]

MenuItem

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]Ext.define('Sencha.view.MenuItem', {
extend: 'Ext.tree.Panel',
alias: 'widget.menuitem',

border: 0,
autoScroll: true,
title: '',
rootVisible: false,

initComponent: function() {
var me = this;

me.callParent(arguments);
}

});[/code]

Criando Controller

Menu

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]Ext.define('Sencha.controller.Menu', {
extend: 'Ext.app.Controller',

models: [
'MenuRoot',
'MenuItem'
],
stores: [
'Menu'
],
views: [
'Menu',
'MenuItem'
],

onPanelRender: function(abstractcomponent, options) {
this.getMenuStore().load(function(records, op, success){

var menuPanel = Ext.ComponentQuery.query('menu')[0];

Ext.each(records, function(root){

var menu = Ext.create('Sencha.view.MenuItem',{
title: root.get('title'),
iconCls: root.get('iconCls')
});

Ext.each(root.items(), function(itens){

Ext.each(itens.data.items, function(item){

menu.getRootNode().appendChild({
text: item.get('text'),
leaf: true,
iconCls: item.get('iconCls'),
id: item.get('id'),
className: item.get('className')
});
});
});

menuPanel.add(menu);
});
});
},

onTreepanelSelect: function(selModel, record, index, options) {
Ext.Msg.alert('You selected the following menu item', record.get('text'));

},

init: function(application) {
this.control({
"menu": {
render: this.onPanelRender
},
"treepanel": {
select: this.onTreepanelSelect
}
});
}

});[/code]

Projeto Completo

Download ou Fork: https://github.com/loiane/sencha-extjs4-examples-architect/tree/master/extras/dynamic_accordion_menu

Arquivos do Sencha Architect 2 inclusos.

Crédito dos Iconshttp://www.famfamfam.com/lab/icons/silk/

Baseado no exemplo do fórum extjs.com.brhttp://www.extjs.com.br/forum/index.php?topic=6544.0

Até a próxima! :)