1. #1
    Sencha User
    Join Date
    Mar 2009
    Posts
    227
    Vote Rating
    0
    SchattenMann is an unknown quantity at this point

      0  

    Default How to: extend form field to get 2 textbox

    How to: extend form field to get 2 textbox


    hi to all

    at this moment i have a particular need in almost all my forms.

    since 1 image is better then 1000 words i'll attach an image of the desired field.

    for what i understand i need to expand a TriggerField to get the buttons(basically the SearchField Example) but the part to have 2 textfields ( the first to display the client ID, editable;the second to display the client Name, disabled) got me totally lost...

    i had never developed my own fields so yah...i'm lost and i'm noob

    if some one could guide me it would be much appreciate.

    tks
    Attached Images

  2. #2
    jay@moduscreate.com's Avatar
    Join Date
    Mar 2007
    Location
    Frederick MD, NYC, DC
    Posts
    16,353
    Vote Rating
    79
    jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all

      0  

    Default


    i would extend container and implement textfield and triggerfield

  3. #3
    Sencha User
    Join Date
    Mar 2009
    Posts
    227
    Vote Rating
    0
    SchattenMann is an unknown quantity at this point

      0  

    Default


    a little vague for my knowledge my friend...

  4. #4
    Sencha User
    Join Date
    Nov 2007
    Location
    London, UK
    Posts
    583
    Vote Rating
    0
    mabello is on a distinguished road

      0  

    Default


    I think
    http://extjs.com/forum/showthread.php?t=33162
    is what are you looking for.
    You have to go thorugh the thread, I have created a small patch for it (see post #44)
    hope thi shelps

  5. #5
    jay@moduscreate.com's Avatar
    Join Date
    Mar 2007
    Location
    Frederick MD, NYC, DC
    Posts
    16,353
    Vote Rating
    79
    jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all jay@moduscreate.com is a name known to all

      0  

    Default


    sorry dude.

    Extend Ext.Container, where the textfield and triggerfield sit side by side(column layout).

    The challenge with doing this is having methods like isValid, markInvalid, clearInvalid, etc.

  6. #6
    Sencha User
    Join Date
    Mar 2009
    Posts
    227
    Vote Rating
    0
    SchattenMann is an unknown quantity at this point

      0  

    Default


    i tried to go nuts and do it myself...

    Code:
    /*
     * Ext JS Library 2.2.1
     * Copyright(c) 2006-2009, Ext JS, LLC.
     * licensing@extjs.com
     * 
     * http://extjs.com/license
     */
    
    Ext.app.SearchField2 = Ext.extend(Ext.form.TwinTriggerField, {
        initComponent : function(){
            Ext.app.SearchField2.superclass.initComponent.call(this);
            this.on('specialkey', function(f, e){
                if(e.getKey() == e.ENTER){
                    this.onTrigger2Click();
                }
            }, this);
        },
    
        validationEvent:false,
        validateOnBlur:false,
        trigger1Class:'x-form-clear-trigger',
        trigger2Class:'x-form-search-trigger',
        hideTrigger1:true,
        width:180,
        hasSearch : true,
        paramName : 'query',
    
        onTrigger1Click : function(){
            if(this.hasSearch){
                this.el.dom.value = '';
                var o = {start: 0};
                this.clearHandler();
            }
        },
    
        onTrigger2Click : function(){
            var v = this.getRawValue();
            if(v.length < 1){
                this.onTrigger1Click();
                return;
            }
            var o = {start: 0};
            this.searchHandler();
        }
    });
    
    Ext.reg('uxMyField', Ext.app.SearchField2);
    
    /**
     * @class Ext.ux.form.FieldPanel
     * @extends Ext.Panel
     * This class enables a form field to be built using multiple fields and other items.
     * This class started as a field extension of panel (provided by extjs.com).
     * @license: BSD
     * @author: Robert B. Williams (extjs id: vtswingkid)
     * @constructor
     * Creates a new FieldPanel
     * @param {Object} config Configuration options
     * @version 0.1.1
     */
    Ext.namespace("Ext.ux.form");
    Ext.ux.form.FieldPanel = Ext.extend(Ext.Panel,  {
        /**
         * @cfg {String} fieldLabel The label text to display next to this field (defaults to '')
         */
        /**
         * @cfg {String} labelStyle A CSS style specification to apply directly to this field's label (defaults to the
         * container's labelStyle value if set, or ''). For example, <code>labelStyle: 'font-weight:bold;'</code>.
         */
        /**
         * @cfg {String} labelSeparator The standard separator to display after the text of each form label (defaults
         * to the value of {@link Ext.layout.FormLayout#labelSeparator}, which is a colon ':' by default).  To display
         * no separator for this field's label specify empty string ''.
         */
        /**
         * @cfg {Boolean} hideLabel True to completely hide the label element (defaults to false)
         */
        /**
         * @cfg {String} clearCls The CSS class used to provide field clearing (defaults to 'x-form-clear-left')
         */
        /**
         * @cfg {String} itemCls An additional CSS class to apply to the wrapper's form item element of this field (defaults 
         * to the container's itemCls value if set, or '').  Since it is applied to the item wrapper, it allows you to write 
         * standard CSS rules that can apply to the field, the label (if specified) or any other element within the markup for 
         * the field. NOTE: this will not have any effect on fields that are not part of a form. Example use:
         * <pre><code>
    // Apply a style to the field's label:
    &lt;style>
        .required .x-form-item-label {font-weight:bold;color:red;}
    &lt;/style>
    
    new Ext.FormPanel({
        height: 100,
        renderTo: document.body,
        items: [{
            xtype: 'textfield',
            fieldLabel: 'Name',
            itemCls: 'required' //this label will be styled
        },{
            xtype: 'textfield',
            fieldLabel: 'Favorite Color'
        }]
    });
    </code></pre>
         */
        /**
         * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password, file (defaults 
         * to "text"). The types "file" and "password" must be used to render those field types currently -- there are 
         * no separate Ext components for those. Note that if you use <tt>inputType:'file'</tt>, {@link #emptyText} 
         * is not supported and should be avoided.
         */
        /**
         * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered,
         * not those which are built via applyTo (defaults to undefined).
         */
        /**
         * @cfg {Mixed} value A value to initialize this field with (defaults to undefined).
         */
        /**
         * @cfg {String} name The field's HTML name attribute (defaults to "").
         */
        /**
         * @cfg {String} cls A custom CSS class to apply to the field's underlying element (defaults to "").
         */
        
        /**
         * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
         */
        invalidClass : "x-form-invalid",
        /**
         * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided
         * (defaults to "The value in this field is invalid")
         */
        invalidText : "The value in this field is invalid",
        /**
         * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
         */
        focusClass : "x-form-focus",
        /**
         * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
          automatic validation (defaults to "keyup").
         */
        validationEvent : "keyup",
        /**
         * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
         */
        validateOnBlur : true,
        /**
         * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation
         * is initiated (defaults to 250)
         */
        validationDelay : 250,
        /**
         * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
         * {tag: "input", type: "text", size: "20", autocomplete: "off"})
         */
        defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
        /**
         * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
         */
        fieldClass : "x-form-field",
        /**
         * @cfg {String} msgTarget The location where error text should display.  Should be one of the following values
         * (defaults to 'qtip'):
         *<pre>
    Value         Description
    -----------   ----------------------------------------------------------------------
    qtip          Display a quick tip when the user hovers over the field
    title         Display a default browser title attribute popup
    under         Add a block div beneath the field containing the error text
    side          Add an error icon to the right of the field with a popup on hover
    [element id]  Add the error text directly to the innerHTML of the specified element
    </pre>
         */
        msgTarget : 'qtip',
        /**
         * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field
         * (defaults to 'normal').
         */
        msgFx : 'normal',
        /**
         * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only
         * sets the element's readOnly DOM attribute.
         */
        readOnly : false,
        /**
         * @cfg {Boolean} disabled True to disable the field (defaults to false).
         */
        disabled : false,
        /**
         * @cfg {String} token The string used to join and separate the values of the individual fields
         * (defaults to ',').
         */
        token: ',',
        
        // private
        isFormField : true,
        
        // private
        hasFocus : false,
    
        // private
        initComponent: function()
        {
            if (!this.items) this.items = [];
            this.items[this.items.length] = {
                xtype: 'component',
                listeners: {
                    beforerender: function(dummy)
                    {
                        this.items.remove(dummy);
                        this.afterChildrenRender(); //fire the childrenrendered event here
                        return false;
                    },
                    scope: this
                }
            };
            Ext.ux.form.FieldPanel.superclass.initComponent.call(this);
            this.addEvents('change', 'invalid', 'valid');
        },
    
        /**
         * Returns the name attribute of the field if available
         * @return {String} name The field name
         */
        getName: function(){
             return this.rendered && this.hiddenField.dom.name ? this.hiddenField.dom.name : (this.hiddenName || '');
        },
    
        // private
        onRender : function(ct, position){
            Ext.ux.form.FieldPanel.superclass.onRender.call(this, ct, position);
            this.hiddenField=this.el.createChild({
                tag: "input",
                type: "hidden",
                value: "",
                name: this.name
            });
            if(this.readOnly){
                this.items.each(function(f){
                    if(f.isFormField){
                        f.readOnly=true;
                    }
                },this);
            }
            if(this.tabIndex !== undefined){
                var i=tabIndex;
                this.items.each(function(f){
                    if(f.isFormField){
                        f.tabIndex=i++;
                    }
                },this);
            }
    
            this.el.addClass([this.fieldClass, this.cls]);
        },
        
        afterChildrenRender: function(){
            this.initValue();
            this.items.each(function(f){
                if(f.isFormField){
                    f.on('change', this.onChange, this);
                    if(f.trigger){
                        f.trigger.on('click', this.onChange, this)
                    }
                }
            },this);
        },
    
        // private
        initValue : function(){
            if(this.value !== undefined){
                this.setValue(this.value);
            }else if(this.hiddenField.dom.value.length > 0 && this.hiddenField.dom.value != this.emptyText){
                this.setValue(this.hiddenField.dom.value);
            }
            // reference to original value for reset
            this.originalValue = this.getValue();
        },
    
        /**
         * Returns true if this field has been changed since it was originally loaded and is not disabled.
         */
        isDirty : function() {
            if(this.disabled) {
                return false;
            }
            return String(this.getValue()) !== String(this.originalValue);
        },
    
        /**
         * Resets the current field value to the originally loaded value and clears any validation messages
         */
        reset : function(){
            this.setValue(this.originalValue);
            this.clearInvalid();
        },
    
        // private
        initEvents : function(){
            Ext.ux.form.FieldPanel.superclass.initEvents.call(this);
    
            // reference to original value for reset
            this.originalValue = this.getValue();
        },
        
        // private
        onChange: function(){
            this.startValue = this.getValue();
            var v = this.getRawValue();
            if (String(v) !== String(this.startValue)) {
                this.setValue(v);
                if (this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur") {
                    this.validate();
                }
                this.fireEvent('change', this, v, this.startValue);
            }
        },
        
        // private
        onEnable : function(){
            this.items.each(function(f){
                if(f.isFormField){
                    f.enable();
                }
            },this);
        },
        
        // private
        onDisable : function(){
            this.items.each(function(f){
                if(f.isFormField){
                    f.disable();
                }
            },this);
        },        
    
        /**
         * Returns whether or not the field value is currently valid
         * @param {Boolean} preventMark True to disable marking the field invalid
         * @return {Boolean} True if the value is valid, else false
         */
        isValid : function(preventMark){
            if(this.disabled){
                return true;
            }
            var restore = this.preventMark;
            this.preventMark = preventMark === true;
            var v = this.validateValue(this.processValue(this.getRawValue()));
            this.preventMark = restore;
            return v;
        },
    
        /**
         * Validates the field value
         * @return {Boolean} True if the value is valid, else false
         */
        validate : function(){
            if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
                this.clearInvalid();
                return true;
            }
            return false;
        },
    
        // protected - should be overridden by subclasses if necessary to prepare raw values for validation
        processValue : function(value){
            return value;
        },
    
        // private
        // Subclasses should provide the validation implementation by overriding this
        validateValue : function(value){
            return true;
        },
    
        /**
         * Mark this field as invalid, using {@link #msgTarget} to determine how to display the error and 
         * applying {@link #invalidClass} to the field's element.
         * @param {String} msg (optional) The validation message (defaults to {@link #invalidText})
         */
        markInvalid : function(msg){
            if(!this.rendered || this.preventMark){ // not rendered
                return;
            }
            this.items.each(function(f){
                if(f.isFormField){
                    f.el.addClass(this.invalidClass);
                }
            },this);
            msg = msg || this.invalidText;
    
            switch(this.msgTarget){
                case 'qtip':
                    this.el.dom.qtip = msg;
                    this.el.dom.qclass = 'x-form-invalid-tip';
                    if(Ext.QuickTips){ // fix for floating editors interacting with DND
                        Ext.QuickTips.enable();
                    }
                    break;
                case 'title':
                    this.el.dom.title = msg;
                    break;
                case 'under':
                    if(!this.errorEl){
                        var elp = this.getErrorCt();
                        if(!elp){ // field has no container el
                            this.el.dom.title = msg;
                            break;
                        }
                        this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
                        this.errorEl.setWidth(elp.getWidth(true)-20);
                    }
                    this.errorEl.update(msg);
                    Ext.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
                    break;
                case 'side':
                    if(!this.errorIcon){
                        var elp = this.getErrorCt();
                        if(!elp){ // field has no container el
                            this.el.dom.title = msg;
                            break;
                        }
                        this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
                    }
                    this.alignErrorIcon();
                    this.errorIcon.dom.qtip = msg;
                    this.errorIcon.dom.qclass = 'x-form-invalid-tip';
                    this.errorIcon.show();
                    this.on('resize', this.alignErrorIcon, this);
                    break;
                default:
                    var t = Ext.getDom(this.msgTarget);
                    t.innerHTML = msg;
                    t.style.display = this.msgDisplay;
                    break;
            }
            this.fireEvent('invalid', this, msg);
        },
        
        // private
        getErrorCt : function(){
            return this.el.findParent('.x-form-element', 5, true) || // use form element wrap if available
                this.el.findParent('.x-form-field-wrap', 5, true);   // else direct field wrap
        },
    
        // private
        alignErrorIcon : function(){
            this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
        },
    
        /**
         * Clear any invalid styles/messages for this field
         */
        clearInvalid : function(){
            if(!this.rendered || this.preventMark){ // not rendered
                return;
            }
            this.items.each(function(f){
                if(f.isFormField){
                    f.el.removeClass(this.invalidClass);
                }
            },this);
            
            switch(this.msgTarget){
                case 'qtip':
                    this.el.dom.qtip = '';
                    break;
                case 'title':
                    this.el.dom.title = '';
                    break;
                case 'under':
                    if(this.errorEl){
                        Ext.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
                    }
                    break;
                case 'side':
                    if(this.errorIcon){
                        this.errorIcon.dom.qtip = '';
                        this.errorIcon.hide();
                        this.un('resize', this.alignErrorIcon, this);
                    }
                    break;
                default:
                    var t = Ext.getDom(this.msgTarget);
                    t.innerHTML = '';
                    t.style.display = 'none';
                    break;
            }
            this.fireEvent('valid', this);
        },
    
        /**
         * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
         * @return {Mixed} value The field value
         */
        getRawValue : function(){
            var v = '';
            if(this.rendered){
                this.items.each(function(f){
                    if(f.isFormField){
                        if(v.length)v+=this.token;
                        v+=f.getValue();
                    }
                },this);
            }else Ext.value(this.value, '');
            if(v === this.emptyText){
                v = '';
            }
            return v;
        },
    
        /**
         * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
         * @return {Mixed} value The field value
         */
        getValue : function(){
            v=this.hiddenField.dom.value;
            if(v === undefined){
                v = '';
            }
            return v;
        },
    
        /**
         * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
         * @param {Mixed} value The value to set
         * @return {Mixed} value The field value that is set
         */
        setRawValue : function(v){
            var val = '';
            var i = 0;
            if(v.length)var vs = v.split(this.token);
            else{
                var vs = [];
                for (i=0; i<this.items.length; i++){
                    vs[i]='';
                }
            }
            i=0;
            this.items.each(function(f)
            {
                if(i>=vs.length)return false;
                if (f.isFormField) {
                    f.setValue(vs[i]);
                    if (val.length) val += this.token;
                    val += vs[i++];
                }
                return true;
            },this);
            return this.hiddenField.dom.value = val;
        },
    
        /**
         * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
         * @param {Mixed} value The value to set
         */
        setValue : function(v){
            this.value = v;
            if(this.rendered){
                this.value=this.setRawValue(v);
                this.validate();
            }
        },
    
        // private
        adjustSize : function(w, h){
            var s = Ext.ux.form.FieldPanel.superclass.adjustSize.call(this, w, h);
            s.width = this.adjustWidth(this.el.dom.tagName, s.width);
            return s;
        },
    
        // private
        adjustWidth : function(tag, w){
            tag = tag.toLowerCase();
            if(typeof w == 'number' && !Ext.isSafari){
                if(Ext.isIE && (tag == 'input' || tag == 'textarea')){
                    if(tag == 'input' && !Ext.isStrict){
                        return this.inEditor ? w : w - 3;
                    }
                    if(tag == 'input' && Ext.isStrict){
                        return w - (Ext.isIE6 ? 4 : 1);
                    }
                    if(tag == 'textarea' && Ext.isStrict){
                        return w-2;
                    }
                }else if(Ext.isOpera && Ext.isStrict){
                    if(tag == 'input'){
                        return w + 2;
                    }
                    if(tag == 'textarea'){
                        return w-2;
                    }
                }
            }
            return w;
        }
    
        /**
         * @cfg {Boolean} autoWidth @hide
         */
        /**
         * @cfg {Boolean} autoHeight @hide
         */
    
        /**
         * @cfg {String} autoEl @hide
         */
    });
    Ext.reg("uxfieldpanel", Ext.ux.form.FieldPanel);
    
    /**
     * @class Ext.ux.form.TimeField
     * @extends Ext.ux.form.FieldPanel
     * This class creates a time field using spinners.
     * @license: BSD
     * @author: Robert B. Williams (extjs id: vtswingkid)
     * @constructor
     * Creates a new FieldPanel
     * @param {Object} config Configuration options
     */
    Ext.namespace("Ext.ux.form");
    
    Ext.ux.form.DuoField = Ext.extend(Ext.ux.form.FieldPanel, {
        border: false,
        baseCls: null,
        layout: 'table',
        layoutConfig: {
            columns: 2
        },
        //width: 180,
        // private
        defaults:{
            maskRe: /[0-9]/,
            maxLength: 3,
            listeners: {
                'focus': function(f){
                    f.selectText();
                }
            }
        },
        initComponent: function()
        {
            this.items = [{
                xtype:'textfield',
                fieldLabel:'teste',
                width:this.firstWidth,
                name: this.name + '-id'
            }, {
                xtype:'uxMyField',
                width:this.secondWidth,
                name: this.name + '-name',
                searchHandler: this.searchHandler,
                clearHandler: this.clearHandler
            }]
            Ext.ux.form.DuoField.superclass.initComponent.call(this);
        }
    });
    Ext.reg('uxDuoField', Ext.ux.form.DuoField);
    
    //totally based on other ppl plugins : SearchField + fieldPanel by vtswingkid
    really messy at this point...but hey: it's my first time :P

    now i have some small issues: don't know how to put the label, fields seems to be readOnly O.o

    if theres any guidance i would appreciate

    i noticed now mabello answer. indeed it seems to be what i want...but just for fun i'll try to make this work.

  7. #7
    Sencha User
    Join Date
    Mar 2009
    Posts
    227
    Vote Rating
    0
    SchattenMann is an unknown quantity at this point

      0  

    Default


    ok just to be sure...

    why does when i press "s" e.getKey() return 115 and "F4" returns 115 too...O.o

    i can't understand

  8. #8
    Sencha User
    Join Date
    Mar 2009
    Posts
    227
    Vote Rating
    0
    SchattenMann is an unknown quantity at this point

      0  

    Default


    i'm having some major (noob) problems with fields communication...

    i created (totally based on other ppl work ) my own xtype that does exactly what i want..

    but now i need them to communicate and thats my problem...

    Code:
    Ext.ux.form.myIdNameField = Ext.extend(Ext.form.TextField, {
    
        initComponent : function(){
            Ext.ux.form.myIdNameField.superclass.initComponent.call(this);
            this.on('keypress', function(f, e){
                if(e.getKey() == 115 && e.button == -1){
                    e.preventDefault();
                    this.append[0].searchHandler();
                }
                if(e.getKey() == 112 && e.button == -1){
                    e.preventDefault();
                    console.debug(this.ownerCt.getForm().findField('firstName').getValue());
                }
            }, this);
        },
        
        append: [{
            xtype: 'myTriggerField',
            width: this.width,
            readOnly:true,
            scope:this,
            cls:'x-item-disabled',
            clearHandler: function(){
                console.debug('clear');
            },
            searchHandler: function(){
                console.debug('search');
            }
        }]
    });
    i need the appended field goes to his "parent" field to get some options like width, height, etc...

    but i don't have a clue how i can do it...the dam scope problems :P

    can anyone give a hand...or two...?

Turkiyenin en sevilen filmlerinin yer aldigi xnxx internet sitemiz olan ve porn sex tarzi bir site olan mobil porno izle sitemiz gercekten dillere destan bir durumda herkesin sevdigi bir site olarak tarihe gececege benziyor. Sitenin en belirgin ozelliklerinden birisi de Turkiyede gercekten kaliteli ve muntazam, duzenli porno izle siteleri olmamasidir. Bu yuzden iste. Ayrica en net goruntu kalitesine sahip adresinde yayinlanmaktadir. Mesela diğer sitelerimizden bahsedecek olursak, en iyi hd porno video arşivine sahip bir siteyiz. "The Best anal porn videos and slut anus, big asses movies set..." hd porno faketaxi