了解如何在Extjs 4.2 MVC模式中引用/ loade /实例化存储模型

时间:2013-05-12 15:34:38

标签: extjs extjs4.2 extjs-mvc wakanda

使用Extjs 4.2

我已经阅读了很多文档,谷歌,论坛试图了解组件如何加载以及放置它们的位置,例如商店,模型等,但仍然困惑。

这是我试图开始工作的一个例子

申请说明

主菜单包含联系人,项目,人员等,应用程序首先加载以显示静态非数据驱动,然后使用点击联系人显示带有联系人列表的网格。然后,用户单击联系人行,并显示弹出编辑视图。

在contactitview中,联系人已加载到表单中,此外表单还有一个加载ContactTypes商店的组合框。 ContactType应设置为该联系人记录的contacttype值。

这是一个常见的方法,考虑到这是一个大型应用程序,我只想在需要时加载数据,即显示视图。

以下是我的一些困惑

  1. 您可以在应用配置中定义所有控制器,商店,模型,视图,但无论您正在查看哪个页面,都会加载所有内容。此外,如果您的商店中有autoLoad:true,那么即使您没有查看该特定视图,也会对数据库进行所有商店的调用。

  2. 在控制器的stores或models属性中指定商店或模型时,具体做什么?它只是让你轻松引用商店而不是实际创建它或创建它,还是只是设置getter和setter函数以方便使用。例如,如果我在控制器的store属性中指定了一个商店,并且autoLoad为true,则加载所有数据而不需要执行任何其他操作。但我真正想要的是,只有当我点击“联系人”并且显示列表视图时才会加载该商店。所以我设置autoLoad:false并在我的list函数中使用this.getStore('Contacts')手动获取存储。这很好用,但是使用store和models的控件的数组属性的目的是什么。我在调试器中看到,如果我不使用存储/模型属性,则会对这些js文件发出get请求。

    对不起,我知道这很多,但对我来说很困惑,并且已经挣扎了一段时间。

  3. 最后,只有当您通过设置autoLoad:false并手动加载来单击“联系人”按钮时,才会加载联系人网格。现在,当用户单击编辑时,记录加载正常,但如何加载组合框然后选择正确的值。我认为我的部分问题是了解商店模型如何加载和实例化。在我的组合框存储属性中,我已将ContactType指定为存储,但我得到错误存储未定义,因此未加载js文件或未实例化存储。


  4. 到目前为止,这是我的代码。

      

    应用代码

    Ext.Loader.setConfig({
        enabled: true,
        paths: {
            'Ext.ux': "lib/extux",
            'Wakanda': "lib/extux/wakanda"
        }
    });
    Ext.application({
        name: 'SimplyFundraising',
        autoCreateViewport: true,
    
        requires: ['Ext.ux.Router', // Require the UX
            'Wakanda.model'
        ],
    
        controllers: ['Contacts'],
    });
    

      

    联系人控制器

    Ext.define('SimplyFundraising.controller.Contacts', {
        extend: 'Ext.app.Controller',
    
    
        views: ['contacts.List', 'contacts.Edit'],
        init: function() {
            this.control({
                'contactslist': {
                    itemdblclick: this.editContact,
                    removeitem: this.removeContact
                },
                'contactslist > toolbar > button[action=create]': {
                    click: this.onCreateContact
                },
                // 'contactsadd button[action=save]': {
                // click: this.doCreateContact
                // },
                'contactsedit button[action=save]': {
                    click: this.updateContact
                }
            });
        },
        list: function() {
    
            var mystore = this.getStore('Contacts')
            mystore.load();
            // mystore.proxy.extraParams = { $expand: 'ContactType'};
            //        var User = this.getContactModel();
            //        User.load(258, {
            //            success: function (user) {
            //                console.log("Loaded user 258: " + user.get('lastName'));
            //            }
            //        });
        },
        editContact: function(grid, record) {
            var view = Ext.widget('contactsedit');
            view.down('form').loadRecord(record);
            this.addnew = false
        },
        removeContact: function(Contact) {
            Ext.Msg.confirm('Remove Contact ' + Contact.data.lastName, 'Are you sure?', function(button) {
                if (button == 'yes') {
                    this.getContactsStore().remove(Contact);
                }
            }, this);
        },
        onCreateContact: function() {
            var view = Ext.widget('contactsedit');
            this.addnew = true
        },
        // doCreateContact: function (button) {
        // var win = button.up('window'),
        // form = win.down('form'),
        // values = form.getValues(),
        // store = this.getContactsStore();
        // if (form.getForm().isValid()) {
        // store.add(values);
        // win.close();
        // }
        // },
        updateContact: function(button) {
            var win = button.up('window'),
                form = win.down('form'),
                record = form.getRecord(),
                values = form.getValues(),
                store = this.getContactsStore();
            if (form.getForm().isValid()) {
                if (this.addnew == true) {
                    store.add(values);
                } else {
                    record.set(values);
                }
                win.close();
            }
        }
    });
    

      

    联系人视图列表

    Ext.define('SimplyFundraising.view.contacts.List', {
        extend: 'Ext.grid.Panel',
        xtype: 'contactslist',
        title: 'All Contacts',
        store: 'Contacts',
        autoHeight: true,
        autoScroll: true,
        viewConfig: {
            loadMask: true
        },
        initComponent: function() {
            this.tbar = [{
                text: 'Create Contact',
                action: 'create'
            }];
            this.columns = [{
                    header: 'Id',
                    dataIndex: '__KEY',
                    width: 50
                }, {
                    header: 'First Name',
                    dataIndex: 'firstName',
                    flex: 1
                }, {
                    header: 'Middle Name',
                    dataIndex: 'middleName',
                    flex: 1
                }, {
                    header: 'Last Name',
                    dataIndex: 'lastName',
                    flex: 1
                },
                {
                    header: 'Type',
                    dataIndex: 'ContactType.name',
                    flex: 1
                }
            ];
            this.addEvents('removeitem');
            this.actions = {
                removeitem: Ext.create('Ext.Action', {
                    text: 'Remove Contact',
                    handler: function() {
                        this.fireEvent('removeitem', this.getSelected())
                    },
                    scope: this
                })
            };
            var contextMenu = Ext.create('Ext.menu.Menu', {
                items: [this.actions.removeitem]
            });
            this.on({
                itemcontextmenu: function(view, rec, node, index, e) {
                    e.stopEvent();
                    contextMenu.showAt(e.getXY());
                    return false;
                }
            });
            this.callParent(arguments);
        },
        getSelected: function() {
            var sm = this.getSelectionModel();
            var rs = sm.getSelection();
            if (rs.length) {
                return rs[0];
            }
            return null;
        }
    });
    

      

    通讯录视图编辑

    Ext.define('SimplyFundraising.view.contacts.Edit', {
        extend: 'Ext.window.Window',
        xtype: 'contactsedit',
        title: 'Edit Contacts',
        layout: 'fit',
        autoShow: true,
        initComponent: function() {
            this.items = [{
                xtype: 'form',
                bodyStyle: {
                    background: 'none',
                    padding: '10px',
                    border: '0'
                },
                items: [{
                    xtype: 'textfield',
                    name: 'firstName',
                    allowBlank: false,
                    fieldLabel: 'Name'
                }, {
                    xtype: 'textfield',
                    name: 'lastName',
                    allowBlank: false,
                    fieldLabel: 'Last Name'
                }, {
                    xtype: 'combobox',
                    fieldLabel: 'Contact Type',
                    name: 'contactType',
                    store: 'ContactTypes',
                    displayField: 'name',
                    typeAhead: true,
                    queryMode: 'local',
                    emptyText: 'Select a type...'
                }]
            }];
            this.buttons = [{
                text: 'Save',
                action: 'save'
            }, {
                text: 'Cancel',
                scope: this,
                handler: this.close
            }];
            this.callParent(arguments);
        }
    });
    

1 个答案:

答案 0 :(得分:2)

不要错过ExtJs。我知道,这可能是一种痛苦......

对于你的问题,我这样解决了:

我有一个列出意大利市政当局的网格。我想按国家,地区和省份进行过滤,因此我将三个组合框放在一个停靠的容器上。在控制器中我有:

     ,init : function (application) {
        this.control({
           ,"#municipalitiesGrid": { afterrender: this.onMunicipalitiesGridAfterRender }
         });
      }
 ,onMunicipalitiesGridAfterRender: function(grid, opts) {
  console.info('GVD.controller.Geo->onMunicipalitiesGridAfterRender');
  var store = grid.getStore(),
      comboCountriesMunicipalities = this.getComboCountriesMunicipalities(),
      storeCountries = comboCountriesMunicipalities.getStore(),
      comboRegionsMunicipalities = this.getComboRegionsMunicipalities(),
      storeRegions = comboRegionsMunicipalities.getStore(),
      comboProvincesMunicipalities = this.getComboProvincesMunicipalities(),
      storeProvinces = comboProvincesMunicipalities.getStore();

      store.clearFilter(true);
      storeCountries.clearFilter(true);
      storeRegions.clearFilter(true);
      storeProvinces.clearFilter(true);

      storeRegions.filter("idCountry", 114); // 114 = Italia
      storeProvinces.filter("idRegion",8);   // 8 = Emilia Romagna
      store.filter("idProvince", 37);        // 37 = Bologna

      storeCountries.load({
        scope: this,
    callback: function(records, operation, success) {
      storeRegions.load({
        scope: this,
        callback: function(records, operation, success) {
          storeProvinces.load({
            scope: this,
        callback: function(records, operation, success) {
           store.load({
             scope: this,
            callback: function(records, operation, success) {
               comboCountriesMunicipalities.setValue(114); // 114 = Italia
               comboRegionsMunicipalities.setValue(8);     // 8 = Emilia Romagna
               comboProvincesMunicipalities.setValue(37);  // 37 = Bologna      
            }
           });
        }
          });
        }
         });
       }
      });
}

在控制器中,当然,我还有其他组合框的'select'事件,所以我可以根据所选的值过滤和重新加载组合。

按照MVC模式,我的商店与此类似:

Ext.define('GVD.store.Municipalities', {
     extend: 'Ext.data.Store'
    ,constructor: function(cfg) {
        console.info('GVD.store.Municipalities->constructor');
        var me = this;
        cfg = cfg || {};
        me.callParent([Ext.apply({
             autoLoad: false
            ,autoSync: true
            ,model: 'GVD.model.Municipalities'
            ,pageSize: 20
        }, cfg)]);
    }
});

和类似的模型:

Ext.define('GVD.model.Municipalities', {
    extend: 'Ext.data.Model',

    fields: [
        {   name: 'id',             type: 'int'         },
        {   name: 'idIstat',        type: 'int'         },
        {   name: 'idCountry',      type: 'int'         },
        {   name: 'idRegion',       type: 'int'         },
        {   name: 'idProvince',     type: 'int'         },
        {   name: 'name',           type: 'string'      },
        {   name: 'chief_town',     type: 'boolean'     },
        {   name: 'altitude_zone',  type: 'int'         },
        {   name: 'altitude',       type: 'int'         },
        {   name: 'coastal',        type: 'int'         },
        {   name: 'mountain',       type: 'int'         },
        {   name: 'surface',        type: 'double'      },
        {   name: 'residents',      type: 'int'         },
        {   name: 'icon',           type: 'string'      }
    ]
    ,proxy: {
        api: {
             create: 'Municipalities.create'
            ,destroy: 'Municipalities.destroy'
            ,read: 'Municipalities.read'
            ,update: 'Municipalities.update'
        }
        ,reader: {
             root: 'data'
            ,totalProperty: 'totalCount'
            ,type: 'json'
        }
        ,type: 'direct'
    }
});

在我的网格中以这种方式引用:

Ext.define('GVD.view.system.geo.ListMunicipalities', {
     autoScroll: true
    ,constrain: true
    ,dockedItems: [{
        xtype: 'topBar'
    },{
         items: [{
                 allowBlank: true
                ,fieldLabel: 'Nazione'
                ,flex: 1
                ,id: 'comboCountriesMunicipalities'
                ,labelAlign: 'right'
                ,labelWidth: 50
                ,listConfig: {
                    getInnerTpl: function() {
                        return  '<img src="resources/images/countries/16/{icon}16.gif" align="left">&nbsp;&nbsp;{italianName}';
                    }
                }
                ,store: Ext.create('GVD.store.Countries', {pageSize: 999})
                ,xtype: 'comboCountries'    
         },{
                 allowBlank: true
                ,fieldLabel: 'Regione'
                ,flex: 1
                ,id: 'comboRegionsMunicipalities'
                ,labelAlign: 'right'
                ,labelWidth: 50
                ,listConfig: {
                    getInnerTpl: function() {
                        return  '<img src="resources/images/regions/16/{icon}16.gif" align="left">&nbsp;&nbsp;{name}';
                    }
                }
                ,store: Ext.create('GVD.store.Regions', {pageSize: 999})
                ,xtype: 'comboRegions'  
         },{
                 allowBlank: true
                ,fieldLabel: 'Provincia'
                ,flex: 1
                ,id: 'comboProvincesMunicipalities'
                ,labelAlign: 'right'
                ,labelWidth: 50
                ,listConfig: {
                    getInnerTpl: function() {
                        return  '<img src="resources/images/provinces/16/{icon}16.gif" align="left">&nbsp;&nbsp;{name}';
                    }
                }
                ,store: Ext.create('GVD.store.Provinces', {pageSize: 999})
                ,xtype: 'comboProvinces'    
         }]
        ,layout: 'hbox'
        ,xtype: 'container'
    }, {
         dock: 'bottom'
        ,itemId: 'municipalitiesPagingToolbar'
        ,store: 'Municipalities'
        ,xtype: 'pagingToolBar'
    }]  
    ,extend: 'Ext.window.Window'
    ,height: 400
    ,icon: 'resources/images/GVD/municipalities16.png'
    ,id: 'listMunicipalities'
    ,items: [{
         columns: [{
            xtype: 'rownumberer'
        },{
             align: 'right'
            ,dataIndex: 'id'
            ,format: '000'
            ,renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
                return '<img src="resources/images/municipalities/16/'+record.data.icon+'16.gif" align="left">&nbsp;&nbsp;'+record.data.id;
            }
            ,text: 'Id'
            ,width: 70
            ,xtype: 'numbercolumn'
        },{
             align: 'right'
            ,dataIndex: 'idIstat'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,format: '000000000'
            ,text: 'Istat'
            ,width: 80
            ,xtype: 'numbercolumn'          
        },{
             dataIndex: 'name'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'string' }
            ,flex: 1
            ,text: 'Denominazione'
            ,xtype: 'gridcolumn'
        },{
             dataIndex: 'chief_town'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,text: 'Capoluogo'
            ,width: 40
            ,xtype: 'numbercolumn'      
            },{
             dataIndex: 'altitude_zone'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,format: '0'
            ,text: 'Zona alt.'
            ,width: 40
            ,xtype: 'numbercolumn'
        },{
             align: 'right'
            ,dataIndex: 'altitude'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,format: '0000'
            ,text: 'Altitudine'
            ,width: 40
            ,xtype: 'numbercolumn'
        },{
             dataIndex: 'coastal'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,format: '0'
            ,text: 'Costiero'
            ,width: 40
            ,xtype: 'numbercolumn'
        },{
             dataIndex: 'mountain'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,format: '0'
            ,text: 'Montano'
            ,width: 40
            ,xtype: 'numbercolumn'
        },{
             align: 'right'
            ,dataIndex: 'surface'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,format: '000,000.00'
            ,text: 'Superficie'
            ,xtype: 'numbercolumn'
        },{
             align: 'right'
            ,dataIndex: 'residents'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'numeric' }
            ,format: '0,000,000'
            ,text: 'residenti'
            ,xtype: 'numbercolumn'
        },{
             dataIndex: 'icon'
            ,editor: { allowBlank: false, selectOnFocus: true }
            ,filter: { type: 'string' }
            ,flex: 1
            ,text: 'Icona'
            ,xtype: 'gridcolumn'
        }]
        ,columnLines: true
        ,emptyText: '<font color="red"><b>Nessun comune in archivio</b></font>'
        ,features: [
            Ext.create('GVD.ux.grid.FiltersFeature', {  
                encode: true, 
                ftype: 'filters', 
                local: false,
                menuFilterText: 'Filtro'
            })
        ]       
        ,id: 'municipalitiesGrid'
        ,plugins: [ Ext.create('Ext.grid.plugin.RowEditing', { ptype: 'rowediting'  })  ]
        ,selModel: { selType: 'checkboxmodel', mode: 'MULTI' },store: 'Provinces'
        ,store: 'Municipalities'
        ,viewConfig: {
             loadingText: 'Caricamento dati'    
            ,stripeRows: true
            ,trackOver: true
        }
        ,xtype: 'grid'
    }]
    ,layout: {
         align: 'stretch'
        ,type: 'vbox'
    }
    ,margin: '0 0 2 0'
    ,maximizable: true
    ,minimizable: true
    ,requires: [
         'GVD.ux.combo.Countries'   
        ,'GVD.ux.combo.Provinces'
        ,'GVD.ux.combo.Regions' 
        ,'GVD.ux.PrintButton'
        ,'GVD.ux.toolbar.BottomBar'
        ,'GVD.ux.toolbar.PagingToolBar'
        ,'GVD.ux.toolbar.TopBar'
    ]   
    ,singleWindow: true
    ,title: 'Elenco comuni'
    ,tools: [
         { xtype: 'printButton',    title: 'Elenco Comuni', tooltip: 'Stampa elenco'    }
        ,{ type: 'help',    xtype: 'tool',  tooltip: 'Guida sulla funzione' }
    ]
    ,width: 760
});

希望这可以提供帮助。

再见