web-dev-qa-db-fra.com

ExtJS 4 - Marquez un astérisque rouge sur un champ requis

J'ai ce problème où j'ai besoin d'ajouter un astérisque rouge à côté d'un fieldLabel lorsqu'un champ est marqué comme "requis" (ou allowBlank: false)

Dans ExtJS3, nous pouvons avoir ce piratage facilement en remplacement de Ext.layout.FormLayout comme suit:

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

Mais cela est impossible dans l'extjs4. FormLayout n'est plus applicable et les étiquettes sont en fait rendu par Ext.form.field.Base En utilisant des mélanges appelés Ext.form.Labelable.

Malheureusement, n'extrave pas le Ext.form.Labelable ou remplacer Ext.form.Labelable est exécutable pour moi. Les composants étendus de Ext.form.field.Base ne reçoit aucun effet de celui-ci. Même si j'ai échangé les mélanges, les modèles ne fonctionnaient toujours pas.

Donc, voici ma solution, où j'ai fait une substitution très dure sur Ext.form.field.Base, et cela fonctionne comme suit ( Découvrez mon exemple )

Ceci est pour EXTJS 4.0.7 uniquement. Pour l'utiliser sur EXTJS 4.0.2A, vous devez modifier le labelableRenderTpl selon celui trouvé dans 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);


})();

Et donc j'ai le bon astérisque ajouté à tous les champs obligatoires.

La question est: y a-t-il un moyen plus facile d'atteindre quelque chose comme ça? Le remplacement est assez dur, mieux si nous pouvons utiliser des mélanges, mais les mélanges ne peuvent pas remplacer le comportement

Remarque

La raison derrière cela est que j'ai des champs personnalisés qui devaient être étendus à partir de la base Text, Combo, FieldContainer. Les mélanges dans le champ étendu ne se gâtent même pas avec le modèle . Ils sont trop têtus. Peut-être la meilleure façon pour l'instant est de remplacer la classe de base ... Découvrez l'exemple de travail

23
Lionel Chan

J'ai une solution peu plus courte. Je suggère d'utiliser l'événement "Beforeadd" de Form comme suit:

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

Voici démo

28
Molecular Man

Vous pouvez toujours remplacer le composant de mise en page similaire à EXTJS3 BUN, étant donné qu'il n'y a pas de liaison de terrain, j'ai envahi Ext.layout.Layout. C'est assez similaire à la solution de Molecle Man, mais c'est plus général. Travailler pour des champs utilisés dans d'autres conteneurs que des formes.

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

Ceci est plus simple que votre solution, mais pas le mieux meilleur, SE exemple également utilisé dans les champs ici

6
nscrob

Pour EXT JS 4.1.1 Cela fonctionne:

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);
    }
});
5
Varun Achar

Vous pouvez également remplacer et ne rien prolonger et ne pas créer une action de contrôleur comme si:

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

Extjs 4.1

Lorsque le champ a une utilisation du champ de terrain:

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

Si le champ n'a pas de champ de terrain, utilisez une combinaison d'options de configuration, la configuration Hidelabel doit être fausse:

//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>'

En outre, vous pouvez mélanger cette solution avec DRASILL Plugin A un moyen facile de personnaliser tous les champs à la fois.

4
Esteban Gatjens

Une approche que vous pourriez trouver plus élégante consiste à ajouter une classe CSS à n'importe quelle étiquette de terrain marquée de allowBlank=false et style votre indicateur obligatoire dans CSS.

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

    extend: 'Ext.form.Panel',

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

});

Vous pouvez ensuite styler votre étiquette de champ dans CSS avec un :after pseudo utilitaire:

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

J'ai fait un plugin pour cela.

Fonctionne ce extjs 4.1 (au moins).

Utilisez si comme ceci:

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

Ou, pour personnaliser l'astérisque:

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

Voici le code du 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;

        }

    });
2
Drasill

Si vous ne voulez rien remplacer, mettez l'astérisque dans le labelseparator:

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

En fait, je pense qu'utiliser fieldubtpl et/ou labelablerendertpl Pour ajouter la * est une approche plus propre que d'utiliser l'auditeur d'événements. Les événements peuvent être arrêtés, les auditeurs peuvent être détachés.

Je pense que la préoccupation de l'OP (Lionel Chan) était que d'utiliser ext.override est un peu happy et il est à 100% à droite. Mais si nous passons le TPL personnalisé dans le niveau de configuration de formulaire, ce n'est pas si mauvais:

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',.....

Il pourrait y avoir quelque chose de mal avec le TPL, je n'ai pas essayé.

1
Chao

Si vous voulez que le rouge * soit affiché pour une étiquette de champ, nous pouvons utiliser le champ de terrain qui le fait.

Par exemple, le code ci-dessous crée un nouveau champ de texte avec nom d'étiquette "nom" et astérisque rouge s'affiche

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
});
0
sandeep vanama

Ils sont tellement de façons de faire cela et peu de ceux que vous pouvez trouver ci-dessus, ce que je suggère:

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

Vous pouvez simplement mettre à la fois des astérisques et un texte d'étiquettes dans une propriété HTML unique.

0
Mayur Gite