ExtJS 4 - 在必填字段上标记红色星号

发布于 2024-12-13 08:36:08 字数 4968 浏览 3 评论 0原文

我遇到这个问题,当字段标记为“必需”(或 allowBlank: false)时,我需要在 fieldLabel 旁边添加一个红色星号。

在 ExtJS3 中,我们可以通过重写Ext.layout.FormLayout,可以轻松实现此 hack,如下所示:

Ext.override(Ext.layout.FormLayout, {
    getTemplateArgs: function(field) {
        var noLabelSep = !field.fieldLabel || field.hideLabel;
        var labelSep = (typeof field.labelSeparator == 'undefined' ? this.labelSeparator : field.labelSeparator);
        if (!field.allowBlank) labelSep += '<span style="color: rgb(255, 0, 0); padding-left: 2px;">*</span>';
        return {
            id: field.id,
            label: field.fieldLabel,
            labelStyle: field.labelStyle||this.labelStyle||'',
            elementStyle: this.elementStyle||'',
            labelSeparator: noLabelSep ? '' : labelSep,
            itemCls: (field.itemCls||this.container.itemCls||'') + (field.hideLabel ? ' x-hide-label' : ''),
            clearCls: field.clearCls || 'x-form-clear-left'
        };
    }
});

但这在 ExtJS4 中是不可能的。 FormLayout 不再适用,标签实际上是由 Ext.form.field.Base 使用名为 Ext.form.Labelable 的 mixins 呈现的>。

遗憾的是,扩展 Ext.form.Labelable 或覆盖 Ext.form.Labelable 对我来说都不可行。来自 Ext.form.field.Base 的扩展组件不会收到任何效果。即使我交换了 mixins,模板仍然无法工作。

所以我的解决方案来了,我对 Ext.form.field.Base 进行了非常严格的覆盖,其工作原理如下(查看我的示例

这仅适用于 ExtJS 4.0.7。要在 ExtJS 4.0.2a 上使用它,您需要根据 4.0.2a /src/form/Labelable.js 中找到的修改 labelableRenderTpl

(function() {

    var overrides =  {
        labelableRenderTpl: [
            '<tpl if="!hideLabel && !(!fieldLabel && hideEmptyLabel)">',
                '<label id="{id}-labelEl"<tpl if="inputId"> for="{inputId}"</tpl> class="{labelCls}"',
                    '<tpl if="labelStyle"> style="{labelStyle}"</tpl>>',
                    '<tpl if="fieldLabel">{fieldLabel}{labelSeparator}</tpl>',
                    '<tpl if="!allowBlank"><span style="color:red">*</span></tpl>',
                '</label>',
            '</tpl>',
            '<div class="{baseBodyCls} {fieldBodyCls}" id="{id}-bodyEl" role="presentation">{subTplMarkup}</div>',
            '<div id="{id}-errorEl" class="{errorMsgCls}" style="display:none"></div>',
            '<div class="{clearCls}" role="presentation"><!-- --></div>',
            {
                compiled: true,
                disableFormats: true
            }
        ],

        /**
         * @protected
         * Generates the arguments for the field decorations {@link #labelableRenderTpl rendering template}.
         * @return {Object} The template arguments
         */
        getLabelableRenderData: function() {
            var me = this,
                labelAlign = me.labelAlign,
                labelCls = me.labelCls,
                labelClsExtra = me.labelClsExtra,
                labelPad = me.labelPad,
                labelStyle;

            // Calculate label styles up front rather than in the Field layout for speed; this
            // is safe because label alignment/width/pad are not expected to change.
            if (labelAlign === 'top') {
                labelStyle = 'margin-bottom:' + labelPad + 'px;';
            } else {
                labelStyle = 'margin-right:' + labelPad + 'px;';
                // Add the width for border-box browsers; will be set by the Field layout for content-box
                if (Ext.isBorderBox) {
                    labelStyle += 'width:' + me.labelWidth + 'px;';
                }
            }

            return Ext.copyTo(
                {
                    inputId: me.getInputId(),
                    fieldLabel: me.getFieldLabel(),
                    labelCls: labelClsExtra ? labelCls + ' ' + labelClsExtra : labelCls,
                    labelStyle: labelStyle + (me.labelStyle || ''),
                    subTplMarkup: me.getSubTplMarkup(),
                    allowBlank: me.allowBlank
                },
                me,
                'hideLabel,hideEmptyLabel,fieldBodyCls,baseBodyCls,errorMsgCls,clearCls,labelSeparator',
                true
            );
        }
    };


    //Both field.Base and FieldContainer are affected, so need to cater for.
    Ext.override(Ext.form.field.Base, overrides);
    Ext.override(Ext.form.FieldContainer, overrides);


})();

并且所以我在所有必填字段中添加了漂亮的星号。

问题是,有没有更简单的方法来实现这样的目标?重写是相当苛刻的,如果我们可以使用 mixins 最好,但是 mixins 不能重写行为

注意

这背后的原因是因为我有自定义字段需要从基本 文本组合FieldContainer扩展字段中的 Mixins 甚至不会扰乱模板。他们只是太固执了。也许现在最好的方法是覆盖基类... 查看工作示例

I have this problem where I need to add a red asterisk beside a fieldLabel when a field is marked as "required" (or allowBlank: false)

In ExtJS3, we can have this hack easily by overriding Ext.layout.FormLayout as follow:

Ext.override(Ext.layout.FormLayout, {
    getTemplateArgs: function(field) {
        var noLabelSep = !field.fieldLabel || field.hideLabel;
        var labelSep = (typeof field.labelSeparator == 'undefined' ? this.labelSeparator : field.labelSeparator);
        if (!field.allowBlank) labelSep += '<span style="color: rgb(255, 0, 0); padding-left: 2px;">*</span>';
        return {
            id: field.id,
            label: field.fieldLabel,
            labelStyle: field.labelStyle||this.labelStyle||'',
            elementStyle: this.elementStyle||'',
            labelSeparator: noLabelSep ? '' : labelSep,
            itemCls: (field.itemCls||this.container.itemCls||'') + (field.hideLabel ? ' x-hide-label' : ''),
            clearCls: field.clearCls || 'x-form-clear-left'
        };
    }
});

But this is impossible in ExtJS4. FormLayout is no longer applicable, and labels are in fact rendered by Ext.form.field.Base by using a mixins called Ext.form.Labelable.

Sadly, neither extending the Ext.form.Labelable or overriding Ext.form.Labelable is workable for me. The extended components from Ext.form.field.Base does not receive any effect from it. Even if I swapped the mixins, the templates still would not work.

So here come my solution, where I did a very harsh override over Ext.form.field.Base, and it works as follow (Check out my example)

This is for ExtJS 4.0.7 only. To use it on ExtJS 4.0.2a you need to modify the labelableRenderTpl according to the one found in 4.0.2a /src/form/Labelable.js

(function() {

    var overrides =  {
        labelableRenderTpl: [
            '<tpl if="!hideLabel && !(!fieldLabel && hideEmptyLabel)">',
                '<label id="{id}-labelEl"<tpl if="inputId"> for="{inputId}"</tpl> class="{labelCls}"',
                    '<tpl if="labelStyle"> style="{labelStyle}"</tpl>>',
                    '<tpl if="fieldLabel">{fieldLabel}{labelSeparator}</tpl>',
                    '<tpl if="!allowBlank"><span style="color:red">*</span></tpl>',
                '</label>',
            '</tpl>',
            '<div class="{baseBodyCls} {fieldBodyCls}" id="{id}-bodyEl" role="presentation">{subTplMarkup}</div>',
            '<div id="{id}-errorEl" class="{errorMsgCls}" style="display:none"></div>',
            '<div class="{clearCls}" role="presentation"><!-- --></div>',
            {
                compiled: true,
                disableFormats: true
            }
        ],

        /**
         * @protected
         * Generates the arguments for the field decorations {@link #labelableRenderTpl rendering template}.
         * @return {Object} The template arguments
         */
        getLabelableRenderData: function() {
            var me = this,
                labelAlign = me.labelAlign,
                labelCls = me.labelCls,
                labelClsExtra = me.labelClsExtra,
                labelPad = me.labelPad,
                labelStyle;

            // Calculate label styles up front rather than in the Field layout for speed; this
            // is safe because label alignment/width/pad are not expected to change.
            if (labelAlign === 'top') {
                labelStyle = 'margin-bottom:' + labelPad + 'px;';
            } else {
                labelStyle = 'margin-right:' + labelPad + 'px;';
                // Add the width for border-box browsers; will be set by the Field layout for content-box
                if (Ext.isBorderBox) {
                    labelStyle += 'width:' + me.labelWidth + 'px;';
                }
            }

            return Ext.copyTo(
                {
                    inputId: me.getInputId(),
                    fieldLabel: me.getFieldLabel(),
                    labelCls: labelClsExtra ? labelCls + ' ' + labelClsExtra : labelCls,
                    labelStyle: labelStyle + (me.labelStyle || ''),
                    subTplMarkup: me.getSubTplMarkup(),
                    allowBlank: me.allowBlank
                },
                me,
                'hideLabel,hideEmptyLabel,fieldBodyCls,baseBodyCls,errorMsgCls,clearCls,labelSeparator',
                true
            );
        }
    };


    //Both field.Base and FieldContainer are affected, so need to cater for.
    Ext.override(Ext.form.field.Base, overrides);
    Ext.override(Ext.form.FieldContainer, overrides);


})();

And so I have the nice asterisk added to all the required fields.

Question is, is there any easier way to achieve something like this? Overriding is pretty harsh, best if we can use mixins, but mixins cannot override the behavior

Note

The reason behind this is because I have customized fields that needed to be extended from the base Text, Combo, FieldContainer. Mixins in the extended field doesn't even mess with the template. They are just too stubborn. Perhaps the best way for now is by overriding the Base class... Check out the working example

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

太傻旳人生 2024-12-20 08:36:09

我为此制作了一个插件。

(至少)适用于 ExtJS 4.1。

像这样使用 if :

Ext.create('Ext.form.Panel', {
  ...
  plugins : "formlabelrequired"
  ...
});

或者,自定义“星号”:

Ext.create('Ext.form.Panel', {
  ...
  plugins : [{ptype:"formlabelrequired", asterisk:" (mandatory)"}]
  ...
});

这是插件的代码:

/**
 * Plugin (ptype = 'formlabelrequired') that adds "asterisk" to labels
 * for Fields with "allowBlank: false".
 */
Ext.define('Ext.ux.plugin.form.LabelRequired', {

        extend: 'Ext.AbstractPlugin',

        alias: 'plugin.formlabelrequired',

        asterisk: ' <span class="required"> *</span>',

        constructor: function() {

            this.callParent(arguments);

        },

        init: function(formPanel) {
            formPanel.on('beforerender', this.onBeforeRender, this);
        },

        /**
         * @private
         * Adds asterisk to labels.
         */
        onBeforeRender: function(formPanel) {

            var i, len, items;

            items = formPanel.query('[allowBlank=false]');

            for (i = 0, len = items.length; i < len; i++) {
                item = items[i];
                item.afterLabelTextTpl = (item.afterLabelTextTpl || "") + this.asterisk;
            }

            return true;

        }

    });

I've made a plugin for this.

Works this ExtJS 4.1 (at least).

Use if like this :

Ext.create('Ext.form.Panel', {
  ...
  plugins : "formlabelrequired"
  ...
});

Or, to customize the "asterisk":

Ext.create('Ext.form.Panel', {
  ...
  plugins : [{ptype:"formlabelrequired", asterisk:" (mandatory)"}]
  ...
});

Here is the code for the plugin :

/**
 * Plugin (ptype = 'formlabelrequired') that adds "asterisk" to labels
 * for Fields with "allowBlank: false".
 */
Ext.define('Ext.ux.plugin.form.LabelRequired', {

        extend: 'Ext.AbstractPlugin',

        alias: 'plugin.formlabelrequired',

        asterisk: ' <span class="required"> *</span>',

        constructor: function() {

            this.callParent(arguments);

        },

        init: function(formPanel) {
            formPanel.on('beforerender', this.onBeforeRender, this);
        },

        /**
         * @private
         * Adds asterisk to labels.
         */
        onBeforeRender: function(formPanel) {

            var i, len, items;

            items = formPanel.query('[allowBlank=false]');

            for (i = 0, len = items.length; i < len; i++) {
                item = items[i];
                item.afterLabelTextTpl = (item.afterLabelTextTpl || "") + this.asterisk;
            }

            return true;

        }

    });
水水月牙 2024-12-20 08:36:09

实际上我认为使用 fieldSubTpl 和/或 labelableRenderTpl 添加 * 是比使用事件侦听器更干净的方法。事件可以停止,监听器可以分离。

我认为 OP(Lionel Chan)担心的是使用 Ext.override 有点老套,他是 100% 正确的。但是,如果我们在表单配置级别传递自定义 tpl,情况并没有那么糟糕:

Ext.create('Ext.form.Panel',{
    defaults:{
        fieldSubTpl:['<input id="{id}" type="{type}" ', 
        '<tpl if="name">name="{name}" </tpl>', 
        '<tpl if="size">size="{size}" </tpl>', 
        '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>', 
        'class="{fieldCls} {typeCls}" autocomplete="off" />',
        '<span>',
        '<tpl if="allowBlank==false">*</tpl>',
        '</span>',
        {
            compiled: true, 
            disableFormats: true
    }]},
    items : [{
        xtype : 'textfield',.....

tpl 可能有问题,我还没有尝试过。

Actually I think using fieldSubTpl and/or labelableRenderTpl to add the * is a cleaner approach than using the event listener. Events can be stopped, listeners can be detached.

I think OP(Lionel Chan)'s concern was that using Ext.override is kinda hacky and he's 100% right. But if we pass the custom tpl in at the form configuration level it's not that bad:

Ext.create('Ext.form.Panel',{
    defaults:{
        fieldSubTpl:['<input id="{id}" type="{type}" ', 
        '<tpl if="name">name="{name}" </tpl>', 
        '<tpl if="size">size="{size}" </tpl>', 
        '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>', 
        'class="{fieldCls} {typeCls}" autocomplete="off" />',
        '<span>',
        '<tpl if="allowBlank==false">*</tpl>',
        '</span>',
        {
            compiled: true, 
            disableFormats: true
    }]},
    items : [{
        xtype : 'textfield',.....

There could be something wrong with the tpl, i haven't tried.

旧情别恋 2024-12-20 08:36:09

如果您不想覆盖任何内容,请将星号放入 labelSeparator 中:

{
  xtype: 'textfield',
  fieldLabel: 'Name',
  name: 'requestor_name',
  allowBlank: false,
  labelSeparator : ': <span style="color:red">*</span>'
}

If you don't want to override anything, put the asterisk in the labelSeparator:

{
  xtype: 'textfield',
  fieldLabel: 'Name',
  name: 'requestor_name',
  allowBlank: false,
  labelSeparator : ': <span style="color:red">*</span>'
}
初雪 2024-12-20 08:36:09

如果您希望字段标签显示红色 *,我们可以使用 fieldlabel 来执行此操作。

例如,以下代码创建标签名称为“Name”的新文本字段,并显示红色星号

var name = new Ext.form.TextField({
    fieldLabel : 'Label<span style=\"color:red;\" ext:qtip=\"This field is required\"> *</span>',
    name : 'name',
    id: 'Name',
    maxLength : 40,
    width : 205,
    allowBlank : false
});

If you want red * to be displayed for a field label we can use fieldlabel which does this.

For example the below code creates new text field with label name "Name" and red asterisk is displayed

var name = new Ext.form.TextField({
    fieldLabel : 'Label<span style=\"color:red;\" ext:qtip=\"This field is required\"> *</span>',
    name : 'name',
    id: 'Name',
    maxLength : 40,
    width : 205,
    allowBlank : false
});
没有心的人 2024-12-20 08:36:09

有很多方法可以做到这一点,但您可以在上面找到其中的几种,我的建议是:

 {
    xtype : 'label',
    html:'<span>First Name</span><span style="color: rgb(255, 0, 0); padding-left: 2px;">*</span>',
    width:50,
 }

您可以简单地将星号和标签文本放在单个 html 属性中。

Their are so many ways to do this and few of which you can find above, what I am suggesting is:

 {
    xtype : 'label',
    html:'<span>First Name</span><span style="color: rgb(255, 0, 0); padding-left: 2px;">*</span>',
    width:50,
 }

Simply you can put both asterisk and Label text in single html property.

我有一个更短的解决方案。我建议使用表单的“beforeadd”事件,如下所示:

Ext.define('Ext.ux.form', {
    extend: 'Ext.form.Panel',
    initComponent: function() {
      this.on('beforeadd', function(me, field){
        if (!field.allowBlank)
          field.labelSeparator += '<span style="color: rgb(255, 0, 0); padding-left: 2px;">*</span>';
      });
      this.callParent(arguments);
    }
});

这是演示

I have a little bit shorter solution. I suggest to use form's 'beforeadd' event like this:

Ext.define('Ext.ux.form', {
    extend: 'Ext.form.Panel',
    initComponent: function() {
      this.on('beforeadd', function(me, field){
        if (!field.allowBlank)
          field.labelSeparator += '<span style="color: rgb(255, 0, 0); padding-left: 2px;">*</span>';
      });
      this.callParent(arguments);
    }
});

Here is demo

三寸金莲 2024-12-20 08:36:08

鉴于没有 fieldLayout,您仍然可以重写类似于 extjs3 面包的布局组件,我已经重写了 Ext.layout.Layout。它与分子人的解决方案非常相似,但更通用。适用于表单以外的其他容器中使用的字段。

Ext.override(Ext.layout.Layout, {
    renderItem: function(item, target, position) {
      if (item && !item.rendered && item.isFieldLabelable && item.fieldLabel && item.allowBlank == false) {
        item.fieldLabel += ' <span class="req" style="color:red">*</span>';
      }
      this.callOverridden(arguments);
    }
});

这比您的解决方案更简单,但不一定更好,例如也在字段集中使用此处

You can still override the layout component similar to extjs3 bun given that there is no fieldLayout, I've overriden Ext.layout.Layout. It's quite similar to molecule man's solution but it's more general. Working for fields used in other containers than forms.

Ext.override(Ext.layout.Layout, {
    renderItem: function(item, target, position) {
      if (item && !item.rendered && item.isFieldLabelable && item.fieldLabel && item.allowBlank == false) {
        item.fieldLabel += ' <span class="req" style="color:red">*</span>';
      }
      this.callOverridden(arguments);
    }
});

This is simpler than your solution but not necesarely better, se example also used in fieldsets here

您还可以覆盖和扩展任何内容,只需创建一个控制器操作,如下所示:

Ext.define('MyApp.controller.MyForm', {
    extend: 'Ext.app.Controller',

    markMandatoryFields: function(field, options) {
        if (field && field.isFieldLabelable && field.fieldLabel && field.allowBlank == false) {
            field.fieldLabel += ' <span class="req" style="color:red">*</span>';
        }
    },

    init: function() {
        this.control({
            "field": {
                beforerender: this.markMandatoryFields
            }
        });
    }
});

You can also override and extend nothing and just create a controller action like so:

Ext.define('MyApp.controller.MyForm', {
    extend: 'Ext.app.Controller',

    markMandatoryFields: function(field, options) {
        if (field && field.isFieldLabelable && field.fieldLabel && field.allowBlank == false) {
            field.fieldLabel += ' <span class="req" style="color:red">*</span>';
        }
    },

    init: function() {
        this.control({
            "field": {
                beforerender: this.markMandatoryFields
            }
        });
    }
});
彩虹直至黑白 2024-12-20 08:36:08

对于Ext JS 4.1.1,这有效:

Ext.define('com.ideas.widgets.Base', {
    override : 'Ext.form.field.Base',
    initComponent : function()
    {
        if(this.allowBlank!==undefined && !this.allowBlank)
        {
            if(!this.labelSeparator)
            {
                this.labelSeparator = "";
            }
            this.labelSeparator += '<span style="color:red">*</span>';
        }
        this.callParent(arguments);
    }
});

For Ext JS 4.1.1 this works:

Ext.define('com.ideas.widgets.Base', {
    override : 'Ext.form.field.Base',
    initComponent : function()
    {
        if(this.allowBlank!==undefined && !this.allowBlank)
        {
            if(!this.labelSeparator)
            {
                this.labelSeparator = "";
            }
            this.labelSeparator += '<span style="color:red">*</span>';
        }
        this.callParent(arguments);
    }
});
森末i 2024-12-20 08:36:08

Extjs 4.1

当字段有 fieldLabel 时使用:

fieldLabel: 'Name',
allowBlank: false,    
afterLabelTextTpl: "<span style="color:red;font-weight:bold" data-qtip="Required">*</span>"

如果字段没有 fieldLabel 使用配置选项的组合,则 hideLabel 配置必须为 false:

//hideLabel: false
name: 'lastName',
emptyText: "Last Name",
allowBlank: false,    
labelWidth: 0,
fieldLabel: '',
hideEmptyLabel: false,
afterLabelTextTpl: '<span style="color:red;font-weight:bold" data-qtip="Required">*</span>'

此外,您可以将此解决方案与 Drasill 插件混合使用,并有一个简单的自定义方法一次所有字段。

Extjs 4.1

When the field has a fieldLabel use:

fieldLabel: 'Name',
allowBlank: false,    
afterLabelTextTpl: "<span style="color:red;font-weight:bold" data-qtip="Required">*</span>"

If the field don't have a fieldLabel use a combination of config options, the hideLabel config must be false:

//hideLabel: false
name: 'lastName',
emptyText: "Last Name",
allowBlank: false,    
labelWidth: 0,
fieldLabel: '',
hideEmptyLabel: false,
afterLabelTextTpl: '<span style="color:red;font-weight:bold" data-qtip="Required">*</span>'

Also, you can mix this solution with Drasill plugin an have a easy way to customise all fields at once.

兮颜 2024-12-20 08:36:08

您可能会发现更优雅的方法是将 CSS 类添加到任何标有 allowBlank=false 的字段标签,并在 CSS 中设置强制指示器的样式。

Ext.define('Ext.ux.form', {

    extend: 'Ext.form.Panel',

    listeners: {
        'beforeadd': function(){
            if (!field.allowBlank) {
                field.labelClsExtra = 'x-required';
            }
        }
    }

});

然后,您可以使用 :after 伪实用程序在 CSS 中设置字段标签的样式:

.x-required:after {
    content: ' *';
    color: red;
    font-weight: bold;
}

An approach that you might find more elegant is adding a css class to any field label that is marked with allowBlank=false and style your mandatory indicator in CSS.

Ext.define('Ext.ux.form', {

    extend: 'Ext.form.Panel',

    listeners: {
        'beforeadd': function(){
            if (!field.allowBlank) {
                field.labelClsExtra = 'x-required';
            }
        }
    }

});

You can then style your field label in CSS with an :after pseudo utility:

.x-required:after {
    content: ' *';
    color: red;
    font-weight: bold;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文