7

使用 Extjs 4.2

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

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

应用说明

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

在 contacteditview 中,联系人被加载到表单中,此外表单还有一个组合框,用于加载 ContactTypes 存储。ContactType 应设置为该联系人记录的contacttype 值。

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

以下是我的一些困惑

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

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

    抱歉,我知道这很多,但这对我来说很困惑,并且已经为此苦苦挣扎了一段时间。

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


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

应用程序代码

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);
    }
});

4

1 回答 1

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      
            }
           });
        }
          });
        }
         });
       }
      });
}

当然,在控制器中,我还有其他侦听器用于组合框的“选择”事件,因此我可以根据所选值过滤和重新加载组合。

遵循 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
});

希望这能有所帮助。

再见

于 2013-08-21T11:21:22.457 回答