• ExtJS Complex data binding


    我们先看一下效果图

    image

    视图方面有一个container,包含了4个组件,一个grid(Editable Grid),一个form(Form),一个view(DataView),一个panel(DataPanel)

    四个组件之间通过一个controller来根据各个组件的事件进行数据的同步显示。

    数据存在于store,store又用到一个model。

    app/view/MainView.js ----- container

    app/view/PersonDataView.js ------- DataView

    app/view/PersonGridView.js --------- Editable Grid

    app/view/PersonFormView.js -------- Form

    app/view/PersonDataPanel.js -------- Data Panel

    app/controller/MainController.js ------- controller

    app/store/PersonStore.js --------- Store

    app/model/PersonModel.js ---------- Model

    app/Application.js -------- Application

    app.js --------------- main entry

    1. app.js

    /*
     * This file is generated and updated by Sencha Cmd. You can edit this file as
     * needed for your application, but these edits will have to be merged by
     * Sencha Cmd when upgrading.
     */
    Ext.scopeCss = true;
    Ext.setGlyphFontFamily('FontAwesome');
    Ext.application({
        name: 'hello',
    
        extend: 'hello.Application'
        
    //    autoCreateViewport: 'hello.view.MainView'
        
        //-------------------------------------------------------------------------
        // Most customizations should be made to hello.Application. If you need to
        // customize this file, doing so below this section reduces the likelihood
        // of merge conflicts when upgrading to new versions of Sencha Cmd.
        //-------------------------------------------------------------------------
    });

    2. Application.js

    /**
     * The main application class. An instance of this class is created by app.js when it calls
     * Ext.application(). This is the ideal place to handle application launch and initialization
     * details.
     */
    
    Ext.define('hello.Application', {
        extend: 'Ext.app.Application',
    
        name: 'hello',
    
        controllers:[
            'MainController'
        ],
        
        launch: function () {
            // TODO - Launch the application
            var me = this,
                ct = Ext.getBody();
            Ext.widget({
                xtype: 'mainview',
                renderTo:ct,
                height:480,
                720,
                frame:true,
                title:'Complex Data Binding Example by Saki',
                glyph:0xf0eb
            });
        }
    });

    launch函数创建了一个widget, xtype为mainview. 该mainview对应MainView.js的alias.

    3. MainView.js

    Ext.define('hello.view.MainView', {
        extend: 'Ext.panel.Panel',
        alias: 'widget.mainview',
        initComponent: function () {
    
            var me = this,
                cfg = {};
            Ext.apply(cfg, {
                layout: {
                    type: 'hbox',
                    align: 'stretch'
                },
                defaults: {
                    flex: 1
                },
                items: [{
                    xtype: 'container',
                    layout: {
                        type: 'vbox',
                        align: 'stretch'
                    },
                    defaults: {
                        flex: 1,
                        margin: 5
                    },
                    items: [{
                        title: 'Editable Grid',
                        xtype: 'persongridview',
                        glyph: 0xf0ce
                    }, {
                        title: 'DataView',
                        glyph: 0xf009,
                        layout: 'fit',
                        items:[{
                            xtype: 'persondataview'
                        }]
                    }]
                },{
                    xtype: 'container',
                    layout: {
                        type: 'vbox',
                        align: 'stretch'
                    },
                    defaults: {
                        flex: 1,
                        margin: 5
                    },
                    items: [{
                        title: 'Form',
                        xtype: 'personformview',
                        glyph: 0xf044,
                        frame: true
                    }, {
                        title: 'Data Panel',
                        xtype: 'personpanelview',
                        glyph: 0xf0f6
                    }]
                }]
    
            });
            Ext.apply(me, cfg);
            me.callParent(arguments);
    
        }
    });

    MainView总共包含了4个视图组件,每个组件通过xtype来指定,分别为4个组件的alias.

    感觉每个组件的别名必须以widget.来打头,不然的话会有问题,可能这是Extjs的一种机制吧。

    4. MainController.js

    Ext.define('hello.controller.MainController', {
        extend:'Ext.app.Controller',
        views:[
            'MainView',
            'PersonGridView',
            'PersonFormView',
            'PersonPanelView',
            'PersonDataView'
        ],
        stores:[
            'PersonStore'
        ],
        refs:[{
            ref:'data',
            selector:'persondataview'
        },{
            ref:'form',
            selector:'personformview'
        },{
            ref:'panel',
            selector:'personpanelview'
        },{
            ref:'grid',
            selector:'persongridview'
        }],
        init:function() {
    
            var me = this;
            me.listen({
                component: {
                    persongridview: {
                        rowselectionchange: 'onRowSelectionChange',
                        edit: 'onGridEdit'
                    },
                    persondataview: {
                        itemselectionchange: 'onItemSelectionChange'
                    },
                    'personformview button': {
                        click: 'onFormButtonClick'
                    },
                    'personformview field': {
                        change: 'onFormFieldChange'
                    }
                }
            });
    
    
        },
        onGridEdit:function(editor,e) {
            var me = this;
            me.getForm().loadRecord(e.record);
            me.getPanel().loadRecord(e.record);
        },
        onFormFieldChange:function(field) {
            var me =this,
                form = me.getForm(),
                record = form.getRecord() || false;
            if(record){
                form.updateRecord();
                me.getPanel().loadRecord(record);
            }
            form.updateUi();
    
        },
        onFormButtonClick:function(btn){
            this.getForm()[btn.itemId +'Record']();
        },
        onRowSelectionChange:function(grid, selected) {
            alert("onRowSelectionChange");
            var me = this,
                record = selected[0];// || false;
            var sm = me.getData().getSelectionModel();
            me.getForm().loadRecord(record);
            alert("getForm ok");
            me.getPanel().loadRecord(record);
            if(record) {
                sm.select(record);//[record]);
            } else {
                sm.deselectAll();
            }
        },
        onItemSelectionChange:function(view, selected) {
            var me = this,
                record = selected[0] || false;
            me.getForm().loadRecord(record);
            me.getPanel().loadRecord(record);
            me.getGrid().getSelectionModel().select(selected);
        }
    });

    MainController里面定义了views,stores,到底有什么用呢?

    看一下官方注释就明白了。

    image

    MainController里面定义了ref,到底有什么用呢?

    通过上面的ref定义,在MainController中就可以使用getData(),getForm(),getGrid(),getPanel()函数,selector就对应的每个视图的alias.

    image

    5. PersonStore.js

    Ext.define('hello.store.PersonStore', {
        extend: 'Ext.data.Store',
        model: 'hello.model.PersonModel',
        autoLoad:true,
    
        data: [
            { id:1,"fname": "Lisa", "lname": "lisa@simpsons.com", "age": "10" },
            { id:2,"fname": "Bart", "lname": "bart@simpsons.com", "age": "12" },
            { id:3,"fname": "Homer", "lname": "homer@simpsons.com", "age": "13" },
            { id:4,"fname": "Tangke", "lname": "marge@simpsons.com", "age": "15" },
        ]
    });

    6. PersonModel.js

    Ext.define('hello.model.PersonModel', {
        extend: 'Ext.data.Model',
        idProperty:'id',
    //    alias:'User',
        fields: [
            { name: 'id', type: 'int' },
            { name: 'fname', type: 'string' },
            { name: 'lname', type: 'string' },
            { name: 'age', type: 'int' }
        ]
    
    
    });

    7. PersonGridView.js

    Ext.define('hello.view.PersonGridView', {
        extend:'Ext.grid.Panel',
        alias:'widget.persongridview',
        uses:[
            'Ext.grid.plugin.CellEditing'
        ],
        initComponent:function() {
    
            var me = this,
                cfg={};
            Ext.apply(cfg, {
                store:Ext.getStore('PersonStore'),
                columns:[{
                    text:'First Name',
                    dataIndex:'fname',
                    editor:{
                        xtype:'textfield'
                    }
                },{
                    text:'Last Name',
                    flex:1,
                    dataIndex:'lname',
                    editor:{
                        xtype:'textfield'
                    }
                },{
                    text:'Age',
                    dataIndex:'age',
                    editor:{
                        xtype:'numberfield'
                    }
                }],
                listeners:{
                    selectionchange:'onSelectionChange'
                },
                setModel:{
                    allowDeselect:true
                },
                plugins:[{
                    ptype:'cellediting',
                    clicksToEdit:2,
                    pluginId:'cellediting'
                }],
                tbar:{
                    xtype:'toolbar',
                    items:['->',{
                        text:'Add Record',
                        itemId:'addRecord',
                        glyph:0xf067,
                        handler:me.onAddRecord,
                        scope:me
    
                    }]
                }
            });
            Ext.apply(me,cfg);
            me.callParent(arguments);
    
        },
        onAddRecord:function() {
            var me = this,
                store = me.getStore(),
                record = store.add({})[0];
            me.getPlugin('cellediting').startEdit(record, 0);
        },
        onSelectionChange:function(selModel, selected, eOpts) {
            this.fireEvent('rowselectionchange', this, selected, eOpts);
        }
    });
    store:Ext.getStore('PersonStore')用于获取数据。
    有些地方用的代码是Ext.data.StoreManager.lookup('PersonStore'),效果是一样的。为什么呢?具体看官方注释:
     
    image

    8. PersonFormView.js

    Ext.define('hello.view.PersonFormView', {
        extend:'Ext.form.Panel',
        alias:'widget.personformview',
        uses:[
            'Ext.form.field.Number'
        ],
        frame:true,
        initComponent:function() {
    
            var me = this,
                cfg={};
            Ext.apply(cfg, {
                defaultType:'textfield',
                defaults: {
                    anchor: '100%'
                },
                bodyPadding:10,
                items:[{
                    fieldLabel:'First Name',
                    name:'fname'
                },{
                    fieldLabel:'Last Name',
                    name:'lname'
                },{
                    fieldLabel:'Age',
                    name:'age',
                    xtype:'numberfield'
                }],
                buttons:[{
                    text:'Rejext',
                    itemId:'reject',
                    disabled:true,
                    glyph:0xf0e2
                },{
                    text:'Commit',
                    itemId:'commit',
                    glyph:0xf00c,
                    disabled:true
                }]
            });
            Ext.apply(me,cfg);
            me.callParent(arguments);
    
        },
        loadRecord:function(record) {
            var me = this;
            if(record) {
                me.callParent([record]);
            } else {
                me.clearValues();
            }
        },
        clearValues:function() {
            var me = this;
            me.getForm()._record = null;
            me.getForm().setValues({
                fname:'',
                lname:'',
                age:undefined
    
            });
            me.uploadUi();
        },
        commitRecord:function() {
            var me = this,
                record = me.getRecord();
            if(record) {
                me.updateRecord();
                record.commit();
                me.updateUi();
            }
        },
        rejectRecord:function() {
            var me = this,
                record = me.getRecord();
            if(record) {
                record.rejectRecord();
                me.loadRecord(record);
                me.updateUi();
            }
        },
        updateUi:function() {
            var me =this,
                record =me.getRecord(),
                disabled=record && record.dirty?false:true;
            Ext.each(me.query('button'), function(btn) {
                btn.setDisabled(disabled);
            })
        }
    });

    9. PersonDataView.js

    Ext.define('hello.view.PersonDataView', {
        extend:'Ext.view.View',
        alias:'widget.persondataview',
        autoscroll:true,
        frame:true,
        initComponent:function() {
    
            var me = this,
                cfg={};
            Ext.apply(cfg, {
                store:Ext.getStore('PersonStore'),
                itemSelector:'div.person-item',
                tpl:[
                    '<tpl for=".">',
                    '<div class="person-item">',
                    '<strong>{fname}.{lname}</strong>{{age}}',
                    '</div>',
                    '</tpl>'
                ],
                listeners: {
                    selectionchange: 'onSelectionChange'
                },
                selModel:{
                    allowDeselect:true
                }
            });
            Ext.apply(me,cfg);
            me.callParent(arguments);
    
        },
        onSelectionChange:function(selModel, selected, eOpts) {
            this.fireEvent('itemselectionchange', this, selected,eOpts);
        }
    });

    10. PersonPanelView.js 

    Ext.define('hello.view.PersonPanelView', {
        extend:'Ext.panel.Panel',
        alias:'widget.personpanelview',
        cls:'person-panel',
        data:{},
        bodyPadding:0,
        frame:true,
        tpl:[
            '<table>',
            '<tr><td>First Name:</td><td><strong>{fname}</strong></td></tr>',
            '<tr><td>Last Name:</td><td><strong>{lname}</strong></td></tr>',
            '</table>'
        ],
        loadRecord:function(record) {
            alert("loadRecord");
            var me = this;
            if(record) {
                me.update(record.getData());
            } else {
                me.update({});
            }
        }
    
    });

    11. 疑问?

    11.1 xtype和alias的对应关系

    看了一个Extjs内部的一些组件,确实也是这样。

    Ext.define('Ext.form.field.Text', {
        extend: 'Ext.form.field.Base',
        alias: 'widget.textfield',
        requires: [
            'Ext.form.field.VTypes',
            'Ext.form.trigger.Trigger',
            'Ext.util.TextMetrics'
        ],
        alternateClassName: [
            'Ext.form.TextField',
            'Ext.form.Text'
        ],
        config: {
            
            hideTrigger: false,
            
            
            triggers: undefined
        },

    11.2 loadRecord的用法

    在PersonFormView中有一个loadRecord的函数,其重写了父类的loadRecord函数。

    image

    在Ext.form.Panel中,

    image

    image

    在PersonPanelView中有也有一个loadRecord函数,但是其父类Ext.panel.Panel并没有loadRecord函数。

    image

    两者传入的参数都是record参数,record是一个model模型。

    image

    {fname},{lname} 分别对应了record model中的fields.

    11.3 getStore

    onAddRecord:function() {
            var me = this,
                store = me.getStore(),
                record = store.add({some:'id'})[0];
            me.getPlugin('cellediting').startEdit(record, 0);
        },

    这里还不是太明白,如果添加一个默认数据。

    11.4 store:

    在PersonDataView和PersonGridView里面分别使用了store配置。其分别派生自Ext.view.View和Ext.grid.Panel.

    Ext.grid.Panel的官方注释:

    store : Ext.data.StoreREQUIRED

    The Store the grid should use as its data source.

    Ext.view.View的官方注释:

    store : Ext.data.StoreREQUIRED

    The Ext.data.Store to bind this DataView to.

    Available since: 2.3.0

  • 相关阅读:
    附近地点搜索 ,地图
    网站访问量
    后台全选功能以及数据的提交方法
    首页banner特效
    等待加载提示
    缩略图轮播
    遍历input。select option 选中的值
    django1补充
    pythonweb框架django框架1
    图书馆管理系统的页面设计
  • 原文地址:https://www.cnblogs.com/mumutouv/p/4279786.html
Copyright © 2020-2023  润新知