Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Forms 如何创建自定义ExtJS表单字段组件?_Forms_Extjs_Extjs4 - Fatal编程技术网

Forms 如何创建自定义ExtJS表单字段组件?

Forms 如何创建自定义ExtJS表单字段组件?,forms,extjs,extjs4,Forms,Extjs,Extjs4,我想使用其中的其他ExtJS组件(例如TreePanel)创建自定义ExtJS表单字段组件。我怎样才能最容易地做到这一点 我已经阅读了的文档,但我不想通过fieldSubTpl定义字段主体。我只想编写创建ExtJS组件的代码,也许还有其他一些获取和设置值的代码 更新:总结目的如下: 这个新的部件应该安装在 表单GUI作为一个字段。它应该有 标签和同一路线(标签, 不需要的其他字段的 进一步的黑客攻击 可能吧,我有 要编写一些getValue,请使用setValue 逻辑。我宁愿将它嵌入到这个组

我想使用其中的其他ExtJS组件(例如TreePanel)创建自定义ExtJS表单字段组件。我怎样才能最容易地做到这一点

我已经阅读了的文档,但我不想通过
fieldSubTpl
定义字段主体。我只想编写创建ExtJS组件的代码,也许还有其他一些获取和设置值的代码

更新:总结目的如下:

  • 这个新的部件应该安装在 表单GUI作为一个字段。它应该有 标签和同一路线(标签, 不需要的其他字段的 进一步的黑客攻击

  • 可能吧,我有 要编写一些getValue,请使用setValue 逻辑。我宁愿将它嵌入到这个组件中,也不愿编写单独的代码,将内容复制到我还必须管理的进一步隐藏的表单字段中


您能再描述一下您的UI需求吗?您确定您甚至需要构建一个完整的字段来支持TreePanel吗?为什么不从普通树面板上的单击处理程序设置隐藏字段的值(请参阅API中的“隐藏”xtype)

为了更全面地回答您的问题,您可以找到许多关于如何扩展ExtJS组件的教程。您可以通过利用Ext.override()或Ext.Extend()方法来实现这一点

但我的感觉是,你的设计可能过于复杂了。您可以通过设置此隐藏字段的值来实现所需的操作。如果您有复杂的数据,可以将该值设置为一些XML或JSON字符串

编辑这里有一些教程。我强烈建议在UI设计中使用KISS规则。保持简单和直接!
我已经做过几次了。以下是我使用的一般过程/伪代码:

  • 创建一个提供最有用重用的字段扩展(如果您只想获取/设置字符串值,通常为Ext.form.TextField)
  • 在字段的
    afterrender
    中,隐藏textfield,并使用
    this.wrap=this.resizeEl=this.positionEl=this.el.wrap()围绕this.el创建一个包装元素
  • 将任何组件渲染到
    this.wrap
    (例如,在配置中使用
    renderTo:this.wrap
  • 覆盖
    getValue
    setValue
    以与手动渲染的组件对话
  • 如果表单的布局发生更改,您可能需要在
    resize
    侦听器中手动调整大小
  • 不要忘记清理您在
    beforeDestroy
    方法中创建的任何组件
我迫不及待地想把我们的代码库切换到ExtJS4,在那里这些事情都很简单


祝你好运

遵循

此代码将创建一个可重用的TypeAhead/Autocomplete样式字段,用于选择语言

var langs = Ext.create( 'Ext.data.store', {
    fields: [ 'label', 'code' ],
    data: [
        { code: 'eng', label: 'English' },
        { code: 'ger', label: 'German' },
        { code: 'chi', label: 'Chinese' },
        { code: 'ukr', label: 'Ukranian' },
        { code: 'rus', label: 'Russian' }
    ]
} );

Ext.define( 'Ext.form.LangSelector', {
    extend: 'Ext.form.field.ComboBox',
    alias: 'widget.LangSelector',
    allowBlank: false,
    hideTrigger: true,
    width: 225,
    displayField: 'label',
    valueField: 'code',
    forceSelection: true,
    minChars: 1,
    store: langs
} );
只需将xtype设置为小部件名称,即可在表单中使用该字段:

{
    xtype: 'LangSelector'
    fieldLabel: 'Language',
    name: 'lang'
}

下面是扩展Ext面板的自定义面板示例。您可以扩展任何组件,检查文档中可以使用的字段、方法和事件

Ext.ns('yournamespace');

yournamespace.MyPanel = function(config) {
    yournamespace.MyPanel.superclass.constructor.call(this, config);
} 

Ext.extend(yournamespace.MyPanel, Ext.Panel, {

    myGlobalVariable : undefined,

    constructor : function(config) {
        yournamespace.MyPanel.superclass.constructor.apply(this, config);
    },

    initComponent : function() {
        this.comboBox = new Ext.form.ComboBox({
            fieldLabel: "MyCombo",
            store: someStore,
            displayField:'My Label',
            typeAhead: true,
            mode: 'local',
            forceSelection: true,
            triggerAction: 'all',
            emptyText:'',
            selectOnFocus:true,
            tabIndex: 1,
            width: 200
        });

        // configure the grid
        Ext.apply(this, {
            listeners: {
                'activate': function(p) {
                    p.doLayout();
                 },
                 single:true
            },

            xtype:"form",
            border: false,
            layout:"absolute",
            labelAlign:"top",
            bodyStyle:"padding: 15px",
            width: 350,
            height: 75,

            items:[{
                xtype:"panel",
                layout:"form",
                x:"10",
                y:"10",
                labelAlign:"top",
                border:false,
                items:[this.comboBox]
            },
            {
                xtype:"panel",
                layout:"form",
                x:"230",
                y:"26",
                labelAlign:"top",
                border:false,
                items:[{
                    xtype:'button',
                    handler: this.someAction.createDelegate(this),
                    text: 'Some Action'
                }]
            }]
        }); // eo apply

        yournamespace.MyPanel.superclass.initComponent.apply(this, arguments);

        this.comboBox.on('select', function(combo, record, index) {
            this.myGlobalVariable = record.get("something");
        }, this);

    }, // eo function initComponent

    someAction : function() {
        //do something
    },

    getMyGlobalVariable : function() {
        return this.myGlobalVariable;
    }

}); // eo extend

Ext.reg('mypanel', yournamespace.MyPanel);

现在这很酷。前几天,我做了一把小提琴来回答另一个问题,然后才意识到我离题了。这是你最后提醒我的问题。谢谢

因此,以下是从另一个组件实现自定义字段所需的步骤:

  • 创建子组件
  • 渲染子组件
  • 确保子组件的大小和大小正确
  • 获取和设置值
  • 转播活动
  • 创建子组件 第一部分,创建组件,很简单。与为任何其他用途创建组件相比,没有什么特别之处

    但是,必须在父字段的
    initComponent
    方法中创建子项(而不是在渲染时)。这是因为外部代码可以合理地期望在
    initComponent
    之后实例化组件的所有依赖对象(例如,向它们添加侦听器)

    此外,您可以对自己友善,在调用super方法之前创建子对象。如果在super方法之后创建子方法,则可能会在子方法尚未实例化时调用字段的
    setValue
    方法(请参见下文)

    initComponent: function() {
        this.childComponent = Ext.create(...);
        this.callParent(arguments);
    }
    
    如您所见,我正在创建一个组件,这在大多数情况下都是您想要的。但是,您也可以尝试组合多个子组件。在这种情况下,我认为尽快回到众所周知的领域是明智的:也就是说,创建一个容器作为子组件,并在其中进行组合

    翻译 然后是渲染问题。起初,我考虑使用渲染容器div,并让子组件在其中渲染自身。但是,在这种情况下,我们不需要模板特性,因此我们也可以使用该方法完全绕过它

    我研究了Ext中的其他组件,以了解它们如何管理子组件的渲染。我在BoundList及其分页工具栏中找到了一个很好的示例(请参阅)。因此,为了获得子组件的标记,我们可以结合使用子组件的方法

    下面是我们字段的
    getSubTplMarkup
    实现:

    getSubTplMarkup: function() {
        // generateMarkup will append to the passed empty array and return it
        var buffer = Ext.DomHelper.generateMarkup(this.childComponent.getRenderTree(), []);
        // but we want to return a single string
        return buffer.join('');
    }
    
    现在,这还不够。我们了解到组件呈现中还有另一个重要部分:调用子组件的方法。幸运的是,我们的自定义字段将在需要时调用自己的方法

    finishRenderChildren: function() {
        this.callParent(arguments);
        this.childComponent.finishRender();
    }
    
    调整大小 现在,我们的子对象将被渲染到正确的位置,但它将不遵守其父字段的大小。对于表单字段来说,这尤其令人恼火,因为这意味着它不会遵守锚定布局

    这很容易解决,我们只需要在调整父字段的大小时调整子字段的大小。从我的经验来看,这是一个很大的改进
    onResize: function(w, h) {
        this.callParent(arguments);
        this.childComponent.setSize(w - this.getLabelWidth(), h);
    }
    
    Ext.define('My.form.field.TodoList', {
        // Extend from Ext.form.field.Base for all the label related business
        extend: 'Ext.form.field.Base'
    
        ,alias: 'widget.todolist'
    
        // --- Child component creation ---
    
        ,initComponent: function() {
    
            // Create the component
    
            // This is better to do it here in initComponent, because it is a legitimate 
            // expectationfor external code that all dependant objects are created after 
            // initComponent (to add listeners, etc.)
    
            // I will use this.grid for semantical access (value), and this.childComponent
            // for generic issues (rendering)
            this.grid = this.childComponent = Ext.create('Ext.grid.Panel', {
                hideHeaders: true
                ,columns: [{dataIndex: 'value', flex: 1}]
                ,store: {
                    fields: ['value']
                    ,data: []
                }
                ,height: this.height || 150
                ,width: this.width || 150
    
                ,tbar: [{
                    text: 'Add'
                    ,scope: this
                    ,handler: function() {
                        var value = prompt("Value?");
                        if (value !== null) {
                            this.grid.getStore().add({value: value});
                        }
                    }
                },{
                    text: "Remove"
                    ,itemId: 'removeButton'
                    ,disabled: true // initial state
                    ,scope: this
                    ,handler: function() {
                        var grid = this.grid,
                            selModel = grid.getSelectionModel(),
                            store = grid.getStore();
                        store.remove(selModel.getSelection());
                    }
                }]
    
                ,listeners: {
                    scope: this
                    ,selectionchange: function(selModel, selection) {
                        var removeButton = this.grid.down('#removeButton');
                        removeButton.setDisabled(Ext.isEmpty(selection));
                    }
                }
            });
    
            // field events
            this.grid.store.on({
                scope: this
                ,datachanged: this.checkChange
            });
    
            this.callParent(arguments);
        }
    
        // --- Rendering ---
    
        // Generates the child component markup and let Ext.form.field.Base handle the rest
        ,getSubTplMarkup: function() {
            // generateMarkup will append to the passed empty array and return it
            var buffer = Ext.DomHelper.generateMarkup(this.childComponent.getRenderTree(), []);
            // but we want to return a single string
            return buffer.join('');
        }
    
        // Regular containers implements this method to call finishRender for each of their
        // child, and we need to do the same for the component to display smoothly
        ,finishRenderChildren: function() {
            this.callParent(arguments);
            this.childComponent.finishRender();
        }
    
        // --- Resizing ---
    
        // This is important for layout notably
        ,onResize: function(w, h) {
            this.callParent(arguments);
            this.childComponent.setSize(w - this.getLabelWidth(), h);
        }
    
        // --- Value handling ---
    
        // This part will be specific to your component of course
    
        ,setValue: function(values) {
            var data = [];
            if (values) {
                Ext.each(values, function(value) {
                    data.push({value: value});
                });
            }
            this.grid.getStore().loadData(data);
        }
    
        ,getValue: function() {
            var data = [];
            this.grid.getStore().each(function(record) {
                data.push(record.get('value'));
            });
            return data;        
        }
    
        ,getSubmitValue: function() {
            return this.getValue().join(',');
        }
    });
    
    Ext.define('MyApp.widget.MyGridField', {
      extend: 'Ext.form.FieldContainer',
      alias: 'widget.mygridfield',
    
      layout: 'fit',
    
      initComponent: function()
      {
        this.callParent(arguments);
    
        this.valueGrid = Ext.widget({
          xtype: 'grid',
          store: Ext.create('Ext.data.JsonStore', {
            fields: ['name', 'value'],
            data: this.value
          }),
          columns: [
            {
              text: 'Name',
              dataIndex: 'name',
              flex: 3
            },
            {
              text: 'Value',
              dataIndex: 'value',
              flex: 1
            }
          ]
        });
    
        this.add(this.valueGrid);
      },
    
      setValue: function(value)
      {
        this.valueGrid.getStore().loadData(value);
      },
    
      getValue: function()
      {
        // left as an exercise for the reader :P
      }
    });
    
    Ext.define('QWA.form.field.DateTime', {
        extend: 'Ext.form.FieldContainer',
        mixins: {
            field: 'Ext.form.field.Field'
        },
        alias: 'widget.datetimefield',
        layout: 'hbox',
        width: 200,
        height: 22,
        combineErrors: true,
        msgTarget: 'side',
        submitFormat: 'c',
    
        dateCfg: null,
        timeCfg: null,
    
        initComponent: function () {
            var me = this;
            if (!me.dateCfg) me.dateCfg = {};
            if (!me.timeCfg) me.timeCfg = {};
            me.buildField();
            me.callParent();
            me.dateField = me.down('datefield')
            me.timeField = me.down('timefield')
    
            me.initField();
        },
    
        //@private
        buildField: function () {
            var me = this;
            me.items = [
            Ext.apply({
                xtype: 'datefield',
                submitValue: false,
                format: 'd.m.Y',
                width: 100,
                flex: 2
            }, me.dateCfg),
            Ext.apply({
                xtype: 'timefield',
                submitValue: false,
                format: 'H:i',
                width: 80,
                flex: 1
            }, me.timeCfg)]
        },
    
        getValue: function () {
            var me = this,
                value,
                date = me.dateField.getSubmitValue(),
                dateFormat = me.dateField.format,
                time = me.timeField.getSubmitValue(),
                timeFormat = me.timeField.format;
            if (date) {
                if (time) {
                    value = Ext.Date.parse(date + ' ' + time, me.getFormat());
                } else {
                    value = me.dateField.getValue();
                }
            }
            return value;
        },
    
        setValue: function (value) {
            var me = this;
            me.dateField.setValue(value);
            me.timeField.setValue(value);
        },
    
        getSubmitData: function () {
            var me = this,
                data = null;
            if (!me.disabled && me.submitValue && !me.isFileUpload()) {
                data = {},
                value = me.getValue(),
                data[me.getName()] = '' + value ? Ext.Date.format(value, me.submitFormat) : null;
            }
            return data;
        },
    
        getFormat: function () {
            var me = this;
            return (me.dateField.submitFormat || me.dateField.format) + " " + (me.timeField.submitFormat || me.timeField.format)
        }
    });
    
    Ext.define('app.view.form.field.CustomField', {
        extend: 'Ext.form.field.Base',
        requires: [
            /* require further components */
        ],
    
        /* custom configs & callbacks */
    
        getValue: function(v){
            /* override function getValue() */
        },
    
        setValue: function(v){
            /* override function setValue() */
        },
    
        getSubTplData: [
           /* most likely needs to be overridden */
        ],
    
        initComponent: function(){
    
            /* further code on event initComponent */
    
            this.callParent(arguments);
        }
    });