Extjs 4 clearable combobox aka Twintriggers example for version 4

I used the clearable combobox extensively in my earlier applications to give users a way to clear a filter on a store, as I would have multiple boxes set up for filter options in a west or east panel next to a grid. When extjs4 rolled out I knew that I had to offer the same usability but wanted to upgrade some apps and my extjs3.x code just did not work. The new clearable combobox is below:

Code: http://www.learnsomethings.com/fcps_checks/js/app.js

Working Example: http://www.learnsomethings.com/fcps_checks/index.html

The code you will need to implement this is below, you may notice three custom configs for the new combobox, these allow it to work as a filter for a form object or grid.

spObject – This is the grid id that you would like to associate this combo with.
spExtraParam – This is the name of the extra param that you would like to clear using this object. Note: you will need the setExtraParam store override to use this.
spForm – Alternately, you can connect the clear function to a form using this config option.

I would have used e.within, however, this built in extjs function did not work in firefox 7 so I had to revert to the good old e.target.name, in case you were wondering.

Ext.define('Ext.ux.ClearableCombo', {
	extend: 'Ext.form.field.ComboBox',
	alias: 'widget.xcombo',
	triggerTip: 'Click to clear selection.',
	spObj:'',
	spForm:'',
	spExtraParam:'',
	qtip:'Clearable Combo Box',
	trigger1Class: 'x-form-select-trigger',
    trigger2Class: 'x-form-clear-trigger',
	onRender: function(ct, position){
		Ext.ux.ClearableCombo.superclass.onRender.call(this, ct, position);
		var id = this.getId();
		this.triggerConfig = {
            tag:'div', cls:'x-form-twin-triggers', style:'display:block;width:46px;', cn:[
            {tag: "img", style: Ext.isIE?'margin-left:-3;height:19px':'', src: Ext.BLANK_IMAGE_URL, id:"trigger1" + id, name:"trigger1" + id, cls: "x-form-trigger " + this.trigger1Class},
            {tag: "img", style: Ext.isIE?'margin-left:-6;height:19px':'', src: Ext.BLANK_IMAGE_URL, id:"trigger2" + id, name:"trigger2" + id, cls: "x-form-trigger " + this.trigger2Class}
        ]};	
this.triggerEl.replaceWith(this.triggerConfig);
this.triggerEl.on('mouseup',function(e){
			
if(e.target.name == "trigger1" + id ){
	this.onTriggerClick();
} else if(e.target.name == "trigger2" + id){
	this.reset();
if(this.spObj!=='' && this.spExtraParam !== ''){
				Ext.getCmp(this.spObj).store.setExtraParam(this.spExtraParam,'');
	Ext.getCmp(this.spObj).store.load()
	}
if(this.spForm!==''){
	Ext.getCmp(this.spForm).getForm().reset();
	}
	}
	},
this);
var trigger1 = Ext.get("trigger1" + id);
var trigger2 = Ext.get("trigger2" + id);
trigger1.addClsOnOver('x-form-trigger-over');
trigger2.addClsOnOver('x-form-trigger-over');
}
});

Here’s how you implement it in the javascript.

var fruits = Ext.create('Ext.data.Store', {
fields: ['fruit'],
data : [
	{"fruit":"Apples"},
	{"fruit":"Oranges"},
	{"fruit":"Grapes"}
]});
   
var fruit_cbo = Ext.create('Ext.ux.ClearableCombo', {
	fieldLabel: 'Choose Year',
	store: fruits,
	queryMode: 'local',
	displayField: 'fruit',
	renderTo: 'clearable_cbo',
	valueField: 'fruit',
	listeners:{select:{fn:function(combo, record, index) {
	// do something!			
	}}}
	});   

A couple of more convenience functions for the extjs4 grid, get record index, object, and convert to params with one easy override

Over the past week I started coding an app that is heavy on grids in extjs4, although I had worked with the extjs4 charting in the past, I was tied to some version 3 applications and could not free up enough to do new development so this switch was a relief. There are however, some methods that I would really like to see as part of the grid, if only to save me from writing out more code than I would like.

The three methods are below.

	
	 Ext.override(Ext.grid.Panel, {
		 // Returns row index of selected record or -1 if there is 
		 // no selection. To use call method like this:
		 // var idx = grid.getSelectedRowIndex();
		getSelectedRowIndex :  function(){
			var r, s;
				r = this.getView().getSelectionModel().getSelection();
				s = this.getStore();
				return s.indexOf(r[0]);
				
		},
		// Returns currently selected record in a grid or -1 if there 
		// is no selected record. To use call method like this:
		// var record = grid.getSelectedRecord();
		getSelectedRecord : function(){
			var r;
			if(this.getView().getSelectionModel().hasSelection()){
				var r = this.getView().getSelectionModel().getSelection();
				return r[0];
			} else {
				return -1;
			}
		},
		// Returns currently selected record as a parameter string which
		// will allow you to pass the row using an ajax call. If there is 
		// no slection this will return -1. To use call like this:
		// var params = grid.getSelectedRecordAsParameters();
		getSelectedRecordAsParameters : function(){
			var r, params;
			if(this.getView().getSelectionModel().hasSelection()){
				r = this.getView().getSelectionModel().getSelection();
				params = '?1=1';
				for (value in r[0].data){
					params = params + '&' + value + '=' + r[0].get(value);
				}
			 } else {
				params = -1;
			 }
				return params;	
		}
	 });

Simple function that will return the selected record index of the extjs4 grid passed to it

Here’s a real time saver, adding this code at the top of the page will add a function named getSelectedRowIndex , and as the name suggests it returns the selected index, or -1 if there is no selection on the grid.

getSelectedRowIndex =  function(grid){
			var r = grid.getSelectionModel().getSelection();
			var s = grid.getStore();
			return s.indexOf(r[0]);
		}

Use it like this

var rowIndex = getSelectedRowIndex(grid);

The extjs4 xtype ‘actioncolumn’ in a nutshell

Say goodbye to renderers and homemade dom insertions to get row level actions in a grid cell, there’s an xtype in extjs 4 that saves time and code. Although this field type has been available since version 3.3, I for one put off diving into the use of this feature as I waited patiently for version 4 and patched my pre 3.3 applications that used renderers to accomplish the same thing, albeit with much more code. The xtype ‘actioncolumn’ adds icons to a column; and these icons each contain a handler with references to the column, row index, and grid object. Just this makes it really handy, but couple that with the getClass function that acts as a renderer on the column and you have a real code saving object! The example grid below will answer the following common action column questions (just click on the lock icon to see it in action, then read further to find out how).

Can I show and hide icons based on a condition in the grid data?

Yes, you can switch icons and hide / show icons based on values in your grid. Inside the getClass function of the action column you can set the the css that will be applied to the action item icon.

The getClass function that controls the locked and unlocked icons is below. There is a boolean value in the closed column that is evaluated for each row. The built in extjs class x-hide-display will remove the icon from a grid cell.

getClass: function(value,metadata,record){
var closed = record.get('closed');
if (closed == 0 ) {
    return 'x-hide-display';	
} else {
    return 'x-grid-center-icon';								
}
}

Can I programmatically switch icons in the action column?

Sure just click on one of the locks above, you can easily change between unlocked and locked icons by committing the new value in closed to the store in your handler. Since you have placed the logic in the getClass function it acts as a renderer and the view is refreshed when the store is updated. The code to commit the new closed value to the store is below.

handler: function(grid, rowIndex, colIndex) {
    var rec = grid.getStore().getAt(rowIndex);
    grid.getSelectionModel().select(rowIndex);
    grid.removeRowCls(grid.getNode(rowIndex),'line-through');
   // This is the line that does the trick
    grid.getStore().getAt(rowIndex).set('closed', 0);									
},

When I click on the icon it fires the action item handler and not the row selection action?

I noticed that too, just add the following line in your action item handler to select the row:

 grid.getSelectionModel().select(rowIndex);

How do I center icons in the action column, and how can I change the cursor?.

Ok, first you will need to add a css class in your main css file so that you may apply it to the icon in the action column. The following class will center the icons and preserve the cursor. You can see from the answer to the first question that we applied the class below in the getClass function.

.x-grid-center-icon{
   display:block; 
   margin:0 auto; 
   text-align:center;
   cursor:hand;
}

This should get you started with the actioncolumn.

Have you switched to extjs 4.x from extjs 2,3.x and realized that your data does not come back from ext.AjaxRequest calls?

Just to be clear from the start this applies to the following extjs 3 code that you may be tempted to lift and place into your brand new extjs 4 app:

Ext.Ajax.request({
url:'some_url.php',                                                           params:{'event':'some_event'},
success: function(action){
var return_obj = Ext.decode(action.responseText);
},
failure: function(action){

} 
});          

One subtle change between extjs 3 and 4 is the fact that method does not default to POST when params are present (it now defaults to the basic form’s method.) So to ensure that your data makes it there and back be sure to specify a method in your form submissions and ajax requests.According to the documentation, this is the default HTTP method to be used for requests. Note that this is case-sensitive and should be all caps (defaults to undefined; if not set but params are present will use “POST”, otherwise will use “GET”.)