1. #31
    Ext User
    Join Date
    Jan 2008
    Posts
    16
    Vote Rating
    0
    ceej is on a distinguished road

      0  

    Default


    Andrewd2: I've just tried loading the data with no luck either, overriding 'InitValue()' enables you to load the data into the field but kills the hole point of using this add-on as it looses the facebook feature.

    Is there any plans on making it so you can load the data into the field as well as entering it???

    Many thanks!

  2. #32
    Ext User
    Join Date
    Oct 2007
    Posts
    63
    Vote Rating
    0
    rtconner is on a distinguished road

      0  

    Default


    Well since the thread creator is not keeping this code up to date, thought I post my version. This version uses the displayTpl, valueField, and displayField abilities. I fixed a prepopulate bug. And cleaned up a few things.

    Usage might look like this:

    Code:
    new Ext.ux.BoxSelect({ store: store, mode: 'local',
    	displayFieldTpl: '<span>{first_name} {last_name}</span>',
    	valueField: 'username',
    	value: [{username: 'foobar', first_name: 'Foo', last_name: 'Bar'}]
    });
    The Code I'm using (though I'm sure it could use some further cleanup)

    Code:
    /**
     * Ext.ux.Box
     * Ext.ux.BoxSelect
     *
     * http://extjs.com/forum/showthread.php?t=33794
     */
    Ext.namespace('Ext.ux');
     
    Ext.ux.Box = Ext.extend(Ext.Component, {
    	initComponent : function(){
    		Ext.ux.Box.superclass.initComponent.call(this);
    	},
    
    	onRender: function(ct, position){
    		Ext.ux.Box.superclass.onRender.call(this, ct, this.maininput);
    		
    		this.addEvents('remove');
    		this.addClass('bit-box');
    		
    		this.el = ct.createChild({ tag: "li" }, this.maininput);
    		this.el.addClassOnOver('bit-hover');
    
    		Ext.apply(this.el, {
    			'focus': function(){ this.down('a.closebutton').focus(); },
    			'dispose': function(){ this.dispose() }.createDelegate(this)
    		});
    
    		this.el.on('click', function(e){
    			this.focus()
    		}, this, {stopEvent:true});
    
    		this.el.update(this.caption);
    
    		this.lnk = this.el.createChild({
    			'tag': 'a',
    			'class': 'closebutton',
    			'href':'#'
    		});
    				
    		this.lnk.on({
    			'click': function(e){
    				e.stopEvent();
    				this.fireEvent('remove', this);
    				this.dispose();
    			},
    			'focus': function(){
    				this.el.addClass("bit-box-focus");
    			},
    			'blur': function(){
    				this.el.removeClass("bit-box-focus");
    			},
    			scope: this
    		});
    		
    		new Ext.KeyMap(this.lnk, [
    			{
    				key: [Ext.EventObject.BACKSPACE, Ext.EventObject.DELETE],
    				fn: function(){
    					this.dispose();
    				}.createDelegate(this)
    			},
    			{
    				key: Ext.EventObject.RIGHT,
    				fn: function(){
    					this.move('right');
    				}.createDelegate(this)
    			},
    			{
    				key: Ext.EventObject.LEFT,
    				fn: function(){
    					this.move('left');
    				}.createDelegate(this)
    			},
    			{
    				key: Ext.EventObject.TAB,
    				fn: function(){
    				}.createDelegate(this)
    			}
    		]).stopEvent = true;
    
    	},
    	
    	move: function(direction) {
    		if(direction == 'left')
    			el = this.el.prev();
    		else
    			el = this.el.next();
    		if(el)
    			el.focus();
    	},
    		
    	dispose: function() {		
    		Ext.fly(this.hidden).remove();
    		this.el.hide({
    			duration: .1,
    			callback: function(){
    				this.move('right');
    				this.destroy()
    			}.createDelegate(this)
    		});
    		return this;
    	}
    });
    
    Ext.ux.BoxSelect = Ext.extend(Ext.form.ComboBox, {
        /**
         * @cfg {Array} value default value(s). Should be an array of objects
         */
        /**
         * @cfg {String} valueField value attribute of the value objects
         */
        /**
         * @cfg {String} displayField display attribute of the value objects
         */
        /**
         * @cfg {String} displayFieldTpl
         */
         
    	initComponent:function() {
    		Ext.apply(this, {
    			selectedValues: {},
    			boxElements: {},
    			current: false,
    			options: {
    				className: 'bit',
    				separator: ','
    			},
    			hideTrigger: true,
    			grow: false
    		});
    			
    		Ext.ux.BoxSelect.superclass.initComponent.call(this);
    	},
    	
    	onRender:function(ct, position) {
    		Ext.ux.BoxSelect.superclass.onRender.call(this, ct, position);
    
    		this.el.removeClass('x-form-text');
    		this.el.className = 'maininput';
    		this.el.dom.name = '';
    		this.el.setWidth(20);
    		this.el.dom.value = ''
    
    		this.holder = this.el.wrap({
    			'tag': 'ul',
    			'class':'holder x-form-text'
    		});
    				
    		this.holder.on('click', function(e){
    			e.stopEvent();
    			if(this.maininput != this.current) this.focus(this.maininput);		 
    		}, this);
    
    		this.maininput = this.el.wrap({
    			'tag': 'li', 'class':'bit-input'
    		});
    		
    		Ext.apply(this.maininput, {
    			'focus': function(){
    				this.focus();
    			}.createDelegate(this)
    		});
    	},
    	
    	// private
    	initValue : function() {
    		if(typeof this.displayFieldTpl  === 'string') {
    		    this.displayFieldTpl = new Ext.XTemplate(this.displayFieldTpl)
    	    }
    
    		if(typeof this.value !== 'undefined') {
                Ext.each(this.value, function(item){
    				if(this.displayFieldTpl) {
    					caption = this.displayFieldTpl.apply(item);
    				} else {
    					caption = item[this.displayField]
    				}
    				this.addBox(item[this.valueField], caption);
                }, this);
    		}
    	},
    	
    	onResize : function( w, h, rw, rh ){
    		this._width = w;
    		Ext.ux.BoxSelect.superclass.onResize.call(this, w, h, rw, rh);
    		this.autoSize();
    	},
    
    	onKeyUp : function(e) {
    		if(this.editable !== false && !e.isSpecialKey()){
    			this.lastKey = e.getKey();
    			if(e.getKey() == e.BACKSPACE && this.el.dom.value.length == 0){
    				e.stopEvent();
    				this.collapse();
    				var el = this.maininput.prev();
    				if(el) el.focus();
    				return;
    			}
    			this.dqTask.delay(this.queryDelay);
    		}
    
    		this.autoSize();
    		Ext.ux.BoxSelect.superclass.onKeyUp.call(this, e);
    	},
    
    	onSelect: function(record, index) {
    		var val = record.data[this.valueField];
    		
    		this.selectedValues[val] = val;
    		
    		if(typeof this.displayFieldTpl  === 'string') {
    		    this.displayFieldTpl = new Ext.XTemplate(this.displayFieldTpl)
    	    }
    		
    		if(!this.boxElements[val]) {
    			var caption;
    			if(this.displayFieldTpl)
    				caption = this.displayFieldTpl.apply(record.data)
    			else if(this.displayField)
    			 	caption = record.data[this.displayField];
    			
    			this.addBox(record.data[this.valueField], caption)
    			
    		}
    		this.collapse();
    		this.setRawValue('');
    		this.lastSelectionText = '';
    		this.applyEmptyText();
    
    		this.autoSize();
    	},
    
    	addBox: function(id, caption){
    		var box = new Ext.ux.Box({
    		    id: 'Box_' + id,
    			maininput: this.maininput,
    			renderTo: this.holder,
    			className: this.options['className'],
    			caption: caption,
    			'value': id,
    			listeners: {
    				'remove': function(box){
    					this.selectedValues[box.value] = null;
    				},
    				scope: this
    			}
    		});
    		box.render();
    
    		box.hidden = this.el.insertSibling({
    			'tag':'input', 
    			'type':'hidden', 
    			'value': id,
    			'name': (this.hiddenName || this.name)
    		},'before', true);
    	},
    	
    	autoSize : function(){
    		if(!this.rendered){ return; }
    		if(!this.metrics){
    			this.metrics = Ext.util.TextMetrics.createInstance(this.el);
    		}
    
    		var el = this.el;
    		var v = el.dom.value;
    		var d = document.createElement('div');
    		d.appendChild(document.createTextNode(v));
    		v = d.innerHTML;
    		d = null;
    		v += "*";
    		var w = Math.min(this._width, Math.max(this.metrics.getWidth(v) +  10, 10));
    		this.el.setWidth(w);
    	},
    
    	getValues: function(){
    		var ret = [];
    		for(var k in this.selectedValues){
    			if(this.selectedValues[k]) {
    				ret.push(this.selectedValues[k]);
    			}
    		}
    		return ret.join(this.options['separator']);
    	}
    });
    
    Ext.reg('boxselect', Ext.ux.BoxSelect);

  3. #33
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default


    Quote Originally Posted by rtconner View Post
    Well since the thread creator is not keeping this code up to date, thought I post my version. This version uses the displayTpl, valueField, and displayField abilities. I fixed a prepopulate bug. And cleaned up a few things.

    Usage might look like this:

    Code:
    new Ext.ux.BoxSelect({ store: store, mode: 'local',
    	displayFieldTpl: '<span>{first_name} {last_name}</span>',
    	valueField: 'username',
    	value: [{username: 'foobar', first_name: 'Foo', last_name: 'Bar'}]
    });

    does your code work as an editor in a gridpanel?

  4. #34
    Ext User
    Join Date
    Aug 2008
    Posts
    6
    Vote Rating
    0
    skitzo is on a distinguished road

      0  

    Default


    rtconner,

    I've been playing with this control since yesterday, and I'm having some trouble with IE6. In IE6 when you add enough items so that a second or third line is needed, the box doesn't grow correctly. It works fine in FF3. Do you see the same problem in IE6?

    Thanks

  5. #35
    Ext User
    Join Date
    Jul 2007
    Posts
    9
    Vote Rating
    0
    scottpederick is on a distinguished road

      0  

    Default IE7 Issue

    IE7 Issue


    If anyone is having an issue with this component in IE7 whereby the trigger's textfield moves in mysterious ways, I've roughly traced it back to the trigger using setDisplayed(false) rather than setVisible(false) - I'm assuming there must be some relative measurement to the trigger that makes it fly off.

    You'll see in the attached screenshots it's ok on view, but as soon as it gets focus it moves down the form (position is ~9997px). Combo still works and the dialog rights itself as soon as it loses focus.

    To replicate I just used the sample and viewed it in IE.

    The hack I used to fix it was to show the trigger in IE then manually set it's visibility: false.

    Code:
    initComponent:function() {
        Ext.apply(this, {
    ...
            hideTrigger: (Ext.isIE ? false : true),
    ...
    },
    
    onRender:function(ct, position) {
        Ext.ux.BoxSelect.superclass.onRender.call(this, ct, position);
    
        if (Ext.isIE)
            this.trigger.setVisible(false);
    ...
    No doubt there's a far cleaner way to do it (css only, even) - but time is against me.
    Attached Images

  6. #36
    Sencha Premium Member tintin's Avatar
    Join Date
    Apr 2008
    Posts
    3
    Vote Rating
    0
    tintin is on a distinguished road

      0  

    Default NEW VERSION

    NEW VERSION


    Hi all,

    Sorry for having been silent for so long.

    I've released a new version today (see first post) with lots of corrections and enhancements. See demo here.

    Thanks for all your advices.
    Usually named efattal
    ExtJS Contributions:
    Ext.ux.ToastWindow | Ext.ux.BoxSelect | Ext.ux.VirtualKeyboard

  7. #37
    Sencha User galdaka's Avatar
    Join Date
    Mar 2007
    Location
    Spain
    Posts
    1,166
    Vote Rating
    -1
    galdaka is an unknown quantity at this point

      0  

    Default


    Hi,

    Window gray problem in IE7.

    Thanks in advance,

  8. #38
    Sencha Premium Member tintin's Avatar
    Join Date
    Apr 2008
    Posts
    3
    Vote Rating
    0
    tintin is on a distinguished road

      0  

    Default


    Quote Originally Posted by galdaka View Post
    Window gray problem in IE7.
    Ouch, I forgot that one. It's OK now.
    Usually named efattal
    ExtJS Contributions:
    Ext.ux.ToastWindow | Ext.ux.BoxSelect | Ext.ux.VirtualKeyboard

  9. #39
    Sencha User
    Join Date
    Mar 2007
    Posts
    767
    Vote Rating
    1
    franklt69 is on a distinguished road

      0  

    Default


    Using new version:


    I don't using Ext.ux.BoxSelect with store, because I addItem for code, and I get error here:


    Code:
            this.store.on('datachanged', function(store){
    
                this.store.each(function(rec){
    				if(this.checkValue(rec.data[this.valueField])){
    					this.removedRecords[rec.data[this.valueField]] = rec;
    					this.store.remove(rec);
    				}
    			}, this);
    		}, this);
    so I modified the code:

    Code:
    if  (this.store){
            this.store.on('datachanged', function(store){
    
                this.store.each(function(rec){
    				if(this.checkValue(rec.data[this.valueField])){
    					this.removedRecords[rec.data[this.valueField]] = rec;
    					this.store.remove(rec);
    				}
    			}, this);
    		}, this);
            }

    a doubt which event I can use to detect a remove item?, I mean I would like when the user close a box do something, how I can get this event?

    regards
    Frank

  10. #40
    Sencha User galdaka's Avatar
    Join Date
    Mar 2007
    Location
    Spain
    Posts
    1,166
    Vote Rating
    -1
    galdaka is an unknown quantity at this point

      0  

    Default


    Hi,

    Sorry for my English,

    Excellent work. One question: Is posible combine free (non-defined) values with pre-defined (In combobox) values?

    I think would be a good idea define a separator as parameter and when you write non-defined value enter separator and make posible expand combobox again for enter new value. This new value will have a diferent css or color (For mark as non-predefined).

    Thanks in advance,