Page 2 of 8 FirstFirst 1234 ... LastLast
Results 11 to 20 of 78

Thread: Grid Filter Menu

  1. #11

    Default

    I get an error on .bind

    Do you have a working example somewhere. Also, I need the icon's.

    Thx

  2. #12
    Sencha User
    Join Date
    Mar 2007
    Location
    Forest Grove, OR
    Posts
    1,038

    Default

    Quote Originally Posted by gkassyou View Post
    I get an error on .bind

    Do you have a working example somewhere. Also, I need the icon's.

    Thx
    That's caused by jQuery-specific syntax in the example code. Ambience, any chance you could clean up those tiny bits so it'll work regardless of which core adapter you use?

  3. #13
    Ext JS Premium Member
    Join Date
    Mar 2007
    Posts
    148

    Default

    Hmm... I'm using jQuery and I'm getting these errors too. In jQuery you can only use bind() on a jQuery object (usually obtained by using the $() function), which doesn't seem to be what's going on here.

    This filtering method though looks extremely useful. It's a problem a lot of people are having to solve. It would be great if something like this could be rolled into Ext in the future!

    Chris

  4. #14
    Ext JS Premium Member
    Join Date
    Mar 2007
    Posts
    148

    Default

    Heh, in fact maybe some kind Premium Member out there could post this in the Feature Request forum - I'm too cheap!

  5. #15

    Default syntax for option

    The filter code looks great! I think I could really use something like this. I'm a noob to ext! I am trying to implement the filter code above and having problems with adding the option to the grid init. Could you supply a code example?

  6. #16
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    Denver, CO
    Posts
    136

    Default

    Sure thing, I'm a bit busy with work right now but I will try to clean it up and make it more Ext friendly soon. .bind() and $() are prototype functions, which are functionally equivalent to function.createDelegate() and Ext.get() respectively.

  7. #17
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    Denver, CO
    Posts
    136

    Default

    Quote Originally Posted by jm_IDT View Post
    The filter code looks great! I think I could really use something like this. I'm a noob to ext! I am trying to implement the filter code above and having problems with adding the option to the grid init. Could you supply a code example?
    Table.js
    Code:
    		var request = Ext.data.Record.create([
    			{name: 'id'},
    			{name: 'timestamp'},
    			{name: 'available'},
    			{name: 'due_date'},
    			{name: 'dispatched'},
    			{name: 'description'},
    			{name: 'rank'},
    			{name: 'ip'},
    			{name: 'username'}
    		]);
    		
    		var reader = new Ext.data.JsonReader({
    			root:          'requests',
    			totalProperty: 'total',
    			id:            'id'
    		}, request);
    		
    		var data_source = new Ext.data.Store({
    			proxy:  new Ext.data.HttpProxy({url: 'index.php?cevent=secure.admin.requestQueue.datasource'}),
    			reader: reader,
    			remoteSort: true
    		});
    		data_source.setDefaultSort('rank', 'asc');
    		
    		var cm = new Ext.grid.ColumnModel([
    			{header: 'ID',           dataIndex: 'id',          width: 50,  filter: 'numeric'},
    			{header: 'Created',      dataIndex: 'timestamp',   width: 65,  filter: 'date'},
    			{header: 'Expires',      dataIndex: 'due_date',    width: 65,  filter: 'date'},
    			{header: 'Available Providers', dataIndex: 'available', width: 52, filter: 'numeric'},
    			{header: 'Dispatched',   dataIndex: 'dispatched',  width: 64,  filter: 'numeric'},
    			{header: 'Username',     dataIndex: 'username',    width: 80,  filter: 'string'},
    			{header: 'Rank',         dataIndex: 'rank',        width: 50,  filter: 'numeric'},
    			{header: 'IP Address',   dataIndex: 'ip',          width: 80,  filter: 'string'},
    			{header: 'Request Text', dataIndex: 'description', width: 600, filter: 'string'}
    		]);
    		cm.defaultSortable = true;
    		
    		var grid = new Ext.grid.Grid('request-queue', {
    			ds: data_source,
    			cm: cm,
    			enableColLock: false,
    			view: new FilteredGridView()
    		});
    UITableSupport.php
    Code:
    class UITableSupport {
    	public static function getDataSql($sql, &$request, $cols = null){
    		$dir = $request->get('dir');
    		
    		$filters = $request->get('filters');
    		if($filters != null && strlen(trim($filters)) > 0)
    			$sql .= " HAVING " . UITableSupport::getHavingClause($filters);
    		
    		if(($cols == null || array_search($request->get('sort'), $cols) !== null) && $dir == 'ASC' || $dir == 'DESC')
    			$sql .= " ORDER BY " . $request->get('sort') . " $dir";
    		
    		if($request->get("start") !== null)
    			$sql .= " LIMIT " . intval($request->get("start")) . ", " . intval($request->get("limit"));
    
    		return $sql;
    	}
    	
    	public static function getSizeSql($sql, &$request){
    		$filters = $request->get('filters');
    		if($filters != null && strlen(trim($filters)) > 0)
    			$sql .= " HAVING " . UITableSupport::getHavingClause($filters);
    		
    		$sql = 'SELECT COUNT(*) AS count FROM (' . $sql . ") q";
    
    		return $sql;
    	}
    	
    	public static function getData($sql, $request, $cols = null, $data = array()){
    		$rs = DBC::newRecordSet(UITableSupport::getDataSql($sql, $request, array('id', 'due_date', 'timestamp', 'name')), $data);
    
    		$results = array();
    		while($rs->next())
    			$results[] = $rs->export();
    			
    		return $results;
    	}
    	
    	public static function getTotal($sql, $request, $data = array()){
    		$rs = DBC::newRecordSet(UITableSupport::getSizeSql($sql, $request), $data);
    		
    		if($rs->next())
    			return $rs->get('count');
    		else
    			return null;
    	}
    	
    	public static function getLimitClause($offset, $limit){
    		if(!is_numeric($offset) || !is_numeric($limit))
    			throw new Exception("Invalid limit specification.");
    		
    		return intval($offset) . ", " . intval($limit);
    	}
    	
    	public static function getOrderClause($orderString){
    		if(strlen($orderString) == 0)
    			return "1";
    		
    		$clauses = array();
    		
    		$orders = explode(';', $orderString);
    		foreach($orders as $order){
    			$params = explode(':', $order);
    			if(preg_match("/[^a-zA-Z_.]/", $params[0]))
    				throw new Exception("Field name contained invalid characters", E_ERROR);
    				
    			array_push($clauses, $params[0] . ' ' . ($params[1] == 'asc' ? 'asc' : 'desc'));
    		}
    		
    		return implode(", ", $clauses);
    	}
    	
    	public static function getHavingClause($filterString){
    		$clauses = array();
    		
    		$matches = explode(';', $filterString);
    		foreach($matches as $filter){
    			$params = explode(':', $filter);
    			if(sizeof($params) < 2)
    				continue;
    			
    			switch($params[1]){
    				case 'like': 
    					array_push($clauses, $params[0] . " LIKE " . DBC::escapeString('%' . $params[2] . '%') . "");
    					break;
    				case 'null':
    					if($params[2] == "null")
    						array_push($clauses, $params[0] . " IS NULL OR LENGTH({$params[0]}) = 0");
    					else
    						array_push($clauses, $params[0] . " IS NOT NULL AND LENGTH({$params[0]}) != 0");
    					break;
    				case 'gt':
    				case 'lt':
    				case 'eq':
    					$subclauses = array();
    					for($i=1; $i < sizeof($params); $i+=2){
    						if(!is_numeric($params[$i + 1]))
    							throw new Exception("Filter parameter must be numeric", E_ERROR);
    
    						switch($params[$i]){
    							case 'gt':
    								array_push($subclauses, "{$params[0]} > " . $params[$i + 1]);
    								break;
    							case 'lt':
    								array_push($subclauses, "{$params[0]} < " . $params[$i + 1]);
    								break;
    							case 'eq':
    								array_push($subclauses, "{$params[0]} = " . $params[$i + 1]);
    								break;
    						}
    					}
    					array_push($clauses, '(' . implode(' AND ', $subclauses) . ')');
    					break;
    				case 'dgt':
    				case 'dlt':
    				case 'deq':
    					$subclauses = array();
    					for($i=1; $i < sizeof($params); $i+=2){
    						switch($params[$i]){
    							case 'dgt':
    								array_push($subclauses, "TIMESTAMPDIFF(DAY, {$params[0]}, " . DBC::escapeString($params[$i + 1]) . ") < 0");
    								break;
    							case 'dlt':
    								array_push($subclauses, "TIMESTAMPDIFF(DAY, {$params[0]}, " . DBC::escapeString($params[$i + 1]) . ") > 0");
    								break;
    							case 'deq':
    								array_push($subclauses, "DATE_FORMAT({$params[0]}, '%Y-%m-%d') = " . DBC::escapeString($params[$i + 1]));
    								break;
    						}
    					}
    					array_push($clauses, '(' . implode(' AND ', $subclauses) . ')');
    					break;
    			}
    		}
    
    		if(sizeof($clauses) > 0)
    			return preg_replace('/\[^\]/', '', implode(" AND ", $clauses));
    		else
    			return '1';
    	}
    }
    ?>
    We are using WACT for this project. The request object basically wraps $_GET and $_POST into a single object where $request->export() returns an array concatenation of the two.

    You will be quick to note that if a user needs to search on a string containing ; or : it will not return the results expected. This run was intended to be used by a very specific admin audience with no need of these characters. I will try to produce a better encoding scheme in the next revision.

    Filter icons http://ambience.v7studios.com/forum/filter_icons.rar. They are very very basic except search.png which comes from the wonderfull (and free) famfamfam.com Silk icon set.
    Last edited by ambience; 19 Apr 2007 at 7:37 AM. Reason: Forgot to mention WACT references.

  8. #18
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    Denver, CO
    Posts
    136

    Default

    Quote Originally Posted by JeffHowden View Post
    That's caused by jQuery-specific syntax in the example code. Ambience, any chance you could clean up those tiny bits so it'll work regardless of which core adapter you use?
    FilteredGridView.js sans-prototype specific functions (I think)
    Code:
    FilteredGridView = function(config){
    	FilteredGridView.superclass.constructor.call(this, config);
    };
    Ext.extend(FilteredGridView, Ext.grid.GridView, {
    	render: function(){
    		FilteredGridView.superclass.render.apply(this, arguments);
    		
    		this.filterMenu = new Ext.menu.Menu();
    		this.fmItems = {
    			sep: this.hmenu.add("separator"),
    			mi:  this.hmenu.add(new Ext.menu.CheckItem({
    				id:"filters", 
    				text: "Filter", 
    				menu: this.filterMenu
    			}))
    		}
    		this.fmItems.mi.on('checkchange', this.updateFilterStatus, this);
    				
    		this.delayedUpdate = new Ext.util.DelayedTask(this.updateFilters, this);
    	},
    	
    	handleHdCtx: function(grid, index){
    		FilteredGridView.superclass.handleHdCtx.apply(this, arguments);
    
    		var filter = this.cm.config[index].filter;
    		if(typeof filter == "string"){
    			filter = this.cm.config[index].filter = new DefaultFilters[filter];
    			filter.fgv = this;
    		}
    		this.activeFilter = filter;
    		this.activeFilter.headerIndex = index;
    		
    		if(filter != null){
    			this.fmItems.mi.setChecked(filter.enabled, true);
    			this.filterMenu.removeAll();	
    			filter.installMenu(this.fmItems.mi);
    			
    			this.fmItems.mi.show();
    			this.fmItems.sep.show();
    		} else {
    			this.fmItems.mi.hide();
    			this.fmItems.sep.hide();
    		}
    		
    		this.hmenu.el.show();
    	},
    		
    	updateFilters: function(){
    		var filters = []
    		var conf = this.cm.config;
    		for(key in conf){
    			var c = conf[key];
    			var f = c.filter;
    			if(f && f.enabled)
    				filters.push(c.dataIndex + ":" + f.serialize());
    		};
    		var ds = this.grid.dataSource;
    		ds.baseParams['filters'] = filters.join(";");
    		ds.reload();
    	},
    	
    	updateFilterStatus: function(item, enabled){
    		this.activeFilter.enabled = enabled;
    		this.updateFilterStyle(this.activeFilter.headerIndex);
    		this.delayedUpdate.delay(500);
    	},
    	
    	updateHeaders: function(){
    		var r = FilteredGridView.superclass.updateHeaders.apply(this, arguments);
    		
    		for(var i=0, l=this.cm.getColumnCount(); i<l; i++)
    			this.updateFilterStyle(i);
    			
    		return r;
    	},
    	
    	updateFilterStyle: function(index){
    		var h = Ext.get(this.getHeaderCell(index).firstChild);
    		if(this.cm.config[index].filter.enabled)
    			h.addClass(this.filteredHeaderClass || 'filtered');
    		else
    			h.removeClass(this.filteredHeaderClass || 'filtered');
    	}
    });
    
    ColumnFilter = function(){};
    ColumnFilter.prototype = {
    	enabled: false,
    	serialize: function(){
    		return 'like:' + encodeURIComponent(this.value);
    	},
    	installMenu: function(rootMenu){}
    }
    
    DefaultFilters = {};
    DefaultFilters['string'] = function(){};
    Ext.extend(DefaultFilters['string'], ColumnFilter,{
    	value: "",
    	installMenu: function(rootItem){
    		var rootMenu = rootItem.menu;
    		
    		var menu = new EditableMenuItem(this.value, {icon: 'skins/default/img/icons/find.png'});
    		menu.on('keyup', function(){
    			this.value = menu.getValue();
    			rootItem.setChecked(true);
    			this.fgv.updateFilterStatus(null, true);
    		}.createDelegate(this));
    		rootMenu.add(menu);
    	}
    });
    DefaultFilters['boolean'] = function(){};
    Ext.extend(DefaultFilters['boolean'], ColumnFilter, {
    	value: false,
    	installMenu: function(rootItem){
    		var rootMenu = rootItem.menu;
    		
    		var optionItems = [
    			new Ext.menu.CheckItem({text: "Yes", group: 'boolean'}),
    			new Ext.menu.CheckItem({text: "No", group: 'boolean', checked: true})];
    		
    		rootMenu.add(optionItems[0]);
    		rootMenu.add(optionItems[1]);
    		optionItems[0].setChecked(this.value, true);
    		
    		var f = function(){
    				this.value = optionItems[0].checked;
    				this.fgv.updateFilterStatus(null, true);
    				rootItem.setChecked(true);
    			}.createDelegate(this);
    			
    		for(var i=0; i<optionItems.length; i++){
    			optionItems[i].on('click', f);
    			optionItems[i].on('checkchange', f);
    		}
    	},
    	serialize: function(){
    		return 'eq:' + (this.value ? '1' : '0');
    	}
    });
    DefaultFilters['null'] = function(){};
    Ext.extend(DefaultFilters['null'], DefaultFilters['boolean'], {
    	serialize: function(){
    		return 'null:' + (this.value ? 'notnull' : 'null');
    	}
    });
    
    DefaultFilters['date'] = function(){};
    Ext.extend(DefaultFilters['date'], ColumnFilter, {
    	installMenu: function(rootItem){
    		var rootMenu = rootItem.menu;
    		
    		var dates = [
    			new Ext.menu.CheckItem({text: "Before", menu: new Ext.menu.DateMenu()}),
    			new Ext.menu.CheckItem({text: "After", menu: new Ext.menu.DateMenu()}),
    			new Ext.menu.CheckItem({text: "On", menu: new Ext.menu.DateMenu()})
    		];
    		
    		var keys = ['before', 'after', 'onDate'];
    		for(var i=0; i<keys.length; i++)
    			if(this[keys[i]]){
    				dates[i].menu.picker.setValue(this[keys[i]]);
    				dates[i].setChecked(true, true);
    			}
    		
    		rootMenu.add(dates[1]);
    		rootMenu.add(dates[0]);
    		rootMenu.add("separator");
    		rootMenu.add(dates[2]);
    		
    		for(var i=0; i<dates.length; i++){
    			dates[i].menu.on('select', function(index){
    				dates[index].setChecked(true);
    				this.fgv.updateFilterStatus(null, true);
    				rootItem.setChecked(true);
    	
    				this[keys[index]] = arguments[2];
    				
    				if(index == 2){
    					dates[0].setChecked(false, true);
    					dates[1].setChecked(false, true);
    					delete this.before;
    					delete this.after;
    				} else {
    					dates[2].setChecked(false, true);
    					delete this.onDate;
    				}
    			}.createDelegate(this, i));
    			
    			dates[i].on('checkchange', function(index){
    				delete this[keys[index]]
    				if(!this[0] && !this[1] && !this[2])
    					rootItem.setChecked(false);
    			}.createDelegate(this, i));
    		};
    	},
    	serialize: function(){
    		var args = [];
    		if(this.before)
    			args = ['dlt:' + this.convertDate(this.before)];
    		if(this.after)
    			args.push('dgt:' + this.convertDate(this.after));
    		if(this.onDate)
    			args = ['deq:' + this.convertDate(this.onDate)];
    		
    		return args.join(':');
    	},
    	convertDate: function(date){
    		date = new Date(date);
    		return date.format('Y-m-d');
    	}
    });
    DefaultFilters['numeric'] = function(){};
    Ext.extend(DefaultFilters['numeric'], ColumnFilter, {
    	installMenu: function(rootItem){
    		var rootMenu = rootItem.menu;
    		
    		var keys = ['gt', 'lt', 'eq'];
    		var fields = [
    			new EditableMenuItem(this.gt || "", {icon: 'skins/default/img/icons/greater_then.png'}),
    			new EditableMenuItem(this.lt || "", {icon: 'skins/default/img/icons/less_then.png'}),
    			new EditableMenuItem(this.eq || "", {icon: 'skins/default/img/icons/equals.png'})
    		];
    
    		rootMenu.add(fields[0]);
    		rootMenu.add(fields[1]);
    		rootMenu.add("separator");
    		rootMenu.add(fields[2]);
    		
    		for(var i=0; i<fields.length; i++)
    			fields[i].on('keyup', function(index, e, input){
    				if(input.value.length > 0 && isFinite(input.value))
    					this[keys[index]] = input.value;
    				else
    					delete this[keys[index]];
    				
    				rootItem.setChecked(false, true);
    				for(var j=0; j<keys.length; j++)
    					if(this[keys[j]]) rootItem.setChecked(true, true);
    
    				this.fgv.updateFilterStatus(null, true);
    			}.createDelegate(this, i));
    	},
    	serialize: function(){
    		var args = [];
    		if(this.lt)
    			args = ['lt:' + this.lt];
    		if(this.gt)
    			args.push('gt:' + this.gt);
    		if(this.eq)
    			args = ['eq:' + this.eq];
    		
    		return args.join(':');
    	}
    });
    
    EditableMenuItem = function(text, config){
    	EditableMenuItem.superclass.constructor.call(this);
    	this.text = text;
    	this.config = config;
    	
    	Ext.apply(this.events, {keyup: true});
    };
    Ext.extend(EditableMenuItem, Ext.menu.BaseItem, {
        itemCls : "x-menu-item",
        hideOnClick: false,
        onRender: function(){
            var s = document.createElement("div");
            s.className = this.itemCls;
            s.style.paddingRight = "10px";
            if(Ext.isGecko)
            	s.style.overflow     = 'auto';
            s.innerHTML = '<img src="' + this.config.icon + '" class="x-menu-item-icon" /><input type="text" style="width: 120px" class="x-menu-input-box" />';
            
            this.field = s.lastChild;
            this.field.value = this.text;
            this.el = s;
            this.relayEvents(Ext.get(this.field), ["keyup"]);
            EditableMenuItem.superclass.onRender.apply(this, arguments);
        },
        getValue: function(){
        	return this.field.value;
        }
    });
    Additionally, I've added a style / config to headers who's columns are filtered. So you can have a style like

    Code:
    .filtered .x-grid-hd-text {
        font-weight: bold;
    }

  9. #19

    Default

    For the "string" filter, is it possible to use an "Ext.form.TextField" instead of "EditableMenuItem" ? It would be simpler to do masking and validation that way (prettier too). I am not sure you can put a "form" inside a "menu" though. ideas?

  10. #20
    Ext User
    Join Date
    Apr 2007
    Location
    Casablanca, Morocco
    Posts
    112

    Default

    Hello ambience,

    nice of you to share...I've tried your code with the array grid example on the demo page, but I get in firebug, the following error:

    g has no properties
    GridView(undefined, undefined)ext-all.js (line 215)
    Grid()ext-all.js (line 211)
    ContentPanel(592, 292)ext-all.js (line 207)
    LayoutRegion(592, 292)ext-all.js (line 199)
    LayoutRegion(Object x=3 y=3 width=594 height=294)ext-all.js (line 199)
    BorderLayout()ext-all.js (line 195)
    LayoutManager(undefined)ext-all.js (line 193)
    BorderLayout(Object center=Object, "grid-panel")ext-all.js (line 195)
    init()gridfilter.js (line 379)
    Observable()ext-all.js (line 15)
    EventManager()ext-all.js (line 17)

    [IMG]chrome://firebug/content/blank.gif[/IMG]


    grid.js
    Code:
    FilteredGridView = function(config){
        FilteredGridView.superclass.constructor.call(this, config);
    };
    Ext.extend(FilteredGridView, Ext.grid.GridView, {
        render: function(){
            FilteredGridView.superclass.render.apply(this, arguments);
            
            this.filterMenu = new Ext.menu.Menu();
            this.fmItems = {
                sep: this.hmenu.add("separator"),
                mi:  this.hmenu.add(new Ext.menu.CheckItem({
                    id:"filters", 
                    text: "Filter", 
                    menu: this.filterMenu
                }))
            }
            this.fmItems.mi.on('checkchange', this.updateFilterStatus, this);
                    
            this.delayedUpdate = new Ext.util.DelayedTask(this.updateFilters, this);
        },
        
        handleHdCtx: function(grid, index){
            FilteredGridView.superclass.handleHdCtx.apply(this, arguments);
    
            var filter = this.cm.config[index].filter;
            if(typeof filter == "string"){
                filter = this.cm.config[index].filter = new DefaultFilters[filter];
                filter.fgv = this;
            }
            this.activeFilter = filter;
            this.activeFilter.headerIndex = index;
            
            if(filter != null){
                this.fmItems.mi.setChecked(filter.enabled, true);
                this.filterMenu.removeAll();    
                filter.installMenu(this.fmItems.mi);
                
                this.fmItems.mi.show();
                this.fmItems.sep.show();
            } else {
                this.fmItems.mi.hide();
                this.fmItems.sep.hide();
            }
            
            this.hmenu.el.show();
        },
            
        updateFilters: function(){
            var filters = []
            var conf = this.cm.config;
            for(key in conf){
                var c = conf[key];
                var f = c.filter;
                if(f && f.enabled)
                    filters.push(c.dataIndex + ":" + f.serialize());
            };
            var ds = this.grid.dataSource;
            ds.baseParams['filters'] = filters.join(";");
            ds.reload();
        },
        
        updateFilterStatus: function(item, enabled){
            this.activeFilter.enabled = enabled;
            this.updateFilterStyle(this.activeFilter.headerIndex);
            this.delayedUpdate.delay(500);
        },
        
        updateHeaders: function(){
            var r = FilteredGridView.superclass.updateHeaders.apply(this, arguments);
            
            for(var i=0, l=this.cm.getColumnCount(); i<l; i++)
                this.updateFilterStyle(i);
                
            return r;
        },
        
        updateFilterStyle: function(index){
            var h = Ext.get(this.getHeaderCell(index).firstChild);
            if(this.cm.config[index].filter.enabled)
                h.addClass(this.filteredHeaderClass || 'filtered');
            else
                h.removeClass(this.filteredHeaderClass || 'filtered');
        }
    });
    
    ColumnFilter = function(){};
    ColumnFilter.prototype = {
        enabled: false,
        serialize: function(){
            return 'like:' + encodeURIComponent(this.value);
        },
        installMenu: function(rootMenu){}
    }
    
    DefaultFilters = {};
    DefaultFilters['string'] = function(){};
    Ext.extend(DefaultFilters['string'], ColumnFilter,{
        value: "",
        installMenu: function(rootItem){
            var rootMenu = rootItem.menu;
            
            var menu = new EditableMenuItem(this.value, {icon: 'skins/default/img/icons/find.png'});
            menu.on('keyup', function(){
                this.value = menu.getValue();
                rootItem.setChecked(true);
                this.fgv.updateFilterStatus(null, true);
            }.createDelegate(this));
            rootMenu.add(menu);
        }
    });
    DefaultFilters['boolean'] = function(){};
    Ext.extend(DefaultFilters['boolean'], ColumnFilter, {
        value: false,
        installMenu: function(rootItem){
            var rootMenu = rootItem.menu;
            
            var optionItems = [
                new Ext.menu.CheckItem({text: "Yes", group: 'boolean'}),
                new Ext.menu.CheckItem({text: "No", group: 'boolean', checked: true})];
            
            rootMenu.add(optionItems[0]);
            rootMenu.add(optionItems[1]);
            optionItems[0].setChecked(this.value, true);
            
            var f = function(){
                    this.value = optionItems[0].checked;
                    this.fgv.updateFilterStatus(null, true);
                    rootItem.setChecked(true);
                }.createDelegate(this);
                
            for(var i=0; i<optionItems.length; i++){
                optionItems[i].on('click', f);
                optionItems[i].on('checkchange', f);
            }
        },
        serialize: function(){
            return 'eq:' + (this.value ? '1' : '0');
        }
    });
    DefaultFilters['null'] = function(){};
    Ext.extend(DefaultFilters['null'], DefaultFilters['boolean'], {
        serialize: function(){
            return 'null:' + (this.value ? 'notnull' : 'null');
        }
    });
    
    DefaultFilters['date'] = function(){};
    Ext.extend(DefaultFilters['date'], ColumnFilter, {
        installMenu: function(rootItem){
            var rootMenu = rootItem.menu;
            
            var dates = [
                new Ext.menu.CheckItem({text: "Before", menu: new Ext.menu.DateMenu()}),
                new Ext.menu.CheckItem({text: "After", menu: new Ext.menu.DateMenu()}),
                new Ext.menu.CheckItem({text: "On", menu: new Ext.menu.DateMenu()})
            ];
            
            var keys = ['before', 'after', 'onDate'];
            for(var i=0; i<keys.length; i++)
                if(this[keys[i]]){
                    dates[i].menu.picker.setValue(this[keys[i]]);
                    dates[i].setChecked(true, true);
                }
            
            rootMenu.add(dates[1]);
            rootMenu.add(dates[0]);
            rootMenu.add("separator");
            rootMenu.add(dates[2]);
            
            for(var i=0; i<dates.length; i++){
                dates[i].menu.on('select', function(index){
                    dates[index].setChecked(true);
                    this.fgv.updateFilterStatus(null, true);
                    rootItem.setChecked(true);
        
                    this[keys[index]] = arguments[2];
                    
                    if(index == 2){
                        dates[0].setChecked(false, true);
                        dates[1].setChecked(false, true);
                        delete this.before;
                        delete this.after;
                    } else {
                        dates[2].setChecked(false, true);
                        delete this.onDate;
                    }
                }.createDelegate(this, i));
                
                dates[i].on('checkchange', function(index){
                    delete this[keys[index]]
                    if(!this[0] && !this[1] && !this[2])
                        rootItem.setChecked(false);
                }.createDelegate(this, i));
            };
        },
        serialize: function(){
            var args = [];
            if(this.before)
                args = ['dlt:' + this.convertDate(this.before)];
            if(this.after)
                args.push('dgt:' + this.convertDate(this.after));
            if(this.onDate)
                args = ['deq:' + this.convertDate(this.onDate)];
            
            return args.join(':');
        },
        convertDate: function(date){
            date = new Date(date);
            return date.format('Y-m-d');
        }
    });
    DefaultFilters['numeric'] = function(){};
    Ext.extend(DefaultFilters['numeric'], ColumnFilter, {
        installMenu: function(rootItem){
            var rootMenu = rootItem.menu;
            
            var keys = ['gt', 'lt', 'eq'];
            var fields = [
                new EditableMenuItem(this.gt || "", {icon: 'skins/default/img/icons/greater_then.png'}),
                new EditableMenuItem(this.lt || "", {icon: 'skins/default/img/icons/less_then.png'}),
                new EditableMenuItem(this.eq || "", {icon: 'skins/default/img/icons/equals.png'})
            ];
    
            rootMenu.add(fields[0]);
            rootMenu.add(fields[1]);
            rootMenu.add("separator");
            rootMenu.add(fields[2]);
            
            for(var i=0; i<fields.length; i++)
                fields[i].on('keyup', function(index, e, input){
                    if(input.value.length > 0 && isFinite(input.value))
                        this[keys[index]] = input.value;
                    else
                        delete this[keys[index]];
                    
                    rootItem.setChecked(false, true);
                    for(var j=0; j<keys.length; j++)
                        if(this[keys[j]]) rootItem.setChecked(true, true);
    
                    this.fgv.updateFilterStatus(null, true);
                }.createDelegate(this, i));
        },
        serialize: function(){
            var args = [];
            if(this.lt)
                args = ['lt:' + this.lt];
            if(this.gt)
                args.push('gt:' + this.gt);
            if(this.eq)
                args = ['eq:' + this.eq];
            
            return args.join(':');
        }
    });
    
    EditableMenuItem = function(text, config){
        EditableMenuItem.superclass.constructor.call(this);
        this.text = text;
        this.config = config;
        
        Ext.apply(this.events, {keyup: true});
    };
    Ext.extend(EditableMenuItem, Ext.menu.BaseItem, {
        itemCls : "x-menu-item",
        hideOnClick: false,
        onRender: function(){
            var s = document.createElement("div");
            s.className = this.itemCls;
            s.style.paddingRight = "10px";
            if(Ext.isGecko)
                s.style.overflow     = 'auto';
            s.innerHTML = '<img src="' + this.config.icon + '" class="x-menu-item-icon" /><input type="text" style="width: 120px" class="x-menu-input-box" />';
            
            this.field = s.lastChild;
            this.field.value = this.text;
            this.el = s;
            this.relayEvents(Ext.get(this.field), ["keyup"]);
            EditableMenuItem.superclass.onRender.apply(this, arguments);
        },
        getValue: function(){
            return this.field.value;
        }
    });
    
    var Example = {
        init : function(){
            // some data yanked off the web
            var myData = [
                ['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
                ['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
                ['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am'],
                ['American Express Company',52.55,0.01,0.02,'9/1 12:00am'],
                ['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am'],
                ['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am'],
                ['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am'],
                ['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am'],
                ['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am'],
                ['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am'],
                ['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am'],
                ['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am'],
                ['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am'],
                ['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
                ['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am'],
                ['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am'],
                ['International Business Machines',81.41,0.44,0.54,'9/1 12:00am'],
                ['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am'],
                ['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am'],
                ['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am'],
                ['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am'],
                ['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am'],
                ['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am'],
                ['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am'],
                ['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am'],
                ['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am'],
                ['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am'],
                ['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am'],
                ['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am'],
                ['Walt Disney Company (The) (Holding Company)',29.89,0.24,0.81,'9/1 12:00am']
            ];
    
            var ds = new Ext.data.Store({
                    proxy: new Ext.data.MemoryProxy(myData),
                    reader: new Ext.data.ArrayReader({}, [
                           {name: 'company'},
                           {name: 'price', type: 'float'},
                           {name: 'change', type: 'float'},
                           {name: 'pctChange', type: 'float'},
                           {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
                      ])
            });
            ds.load();
    
            // example of custom renderer function
            function italic(value){
                return '<i>' + value + '</i>';
            }
    
            // example of custom renderer function
            function change(val){
                if(val > 0){
                    return '<span style="color:green;">' + val + '</span>';
                }else if(val < 0){
                    return '<span style="color:red;">' + val + '</span>';
                }
                return val;
            }
            // example of custom renderer function
            function pctChange(val){
                if(val > 0){
                    return '<span style="color:green;">' + val + '%</span>';
                }else if(val < 0){
                    return '<span style="color:red;">' + val + '%</span>';
                }
                return val;
            }
    
            // the DefaultColumnModel expects this blob to define columns. It can be extended to provide
            // custom or reusable ColumnModels
            var colModel = new Ext.grid.ColumnModel([
                {header: "Company", width: 260, sortable: true, locked:false, dataIndex: 'company', filter: 'string'},
                {header: "Price", width: 75, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price',filter: 'numeric'},
                {header: "Change", width: 75, sortable: true, renderer: change, dataIndex: 'change',filter: 'numeric'},
                {header: "% Change", width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange',filter: 'numeric'},
                {header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange',filter: 'date'}
            ]);
    
            var grid = new Ext.grid.Grid('example-grid', {
                ds: ds,
                cm: colModel,
                enableColLock: false,
                view: new FilteredGridView()
            });
            
             var layout = Ext.BorderLayout.create({
                center: {
                    margins:{left:3,top:3,right:3,bottom:3},
                    panels: [new Ext.GridPanel(grid)]
                }
            }, 'grid-panel');
    
            grid.render();
    
            grid.getSelectionModel().selectFirstRow();
        }
    };
    Ext.onReady(Example.init, Example);
    grid.html:
    Code:
    <html>
    
    <head>
    
    <link rel="stylesheet" type="text/css" href="ext-1.0-beta1/resources/css/ext-all.css" />
    
    <!-- LIBS -->    
    <script type="text/javascript" src="ext-1.0-beta1/yui-utilities.js"></script>   
    <script type="text/javascript" src="ext-1.0-beta1/ext-yui-adapter.js"></script>     
    <script type="text/javascript" src="ext-1.0-beta1/ext-all.js"></script>
        
    <script type="text/javascript" src="gridfilter.js"></script>
    <link rel="stylesheet" type="text/css" href="ext-1.0-beta1/examples/grid/grid-examples.css" />
    
    <!-- Common Styles for the examples -->
    <link rel="stylesheet" type="text/css" href="ext-1.0-beta1/examples/examples.css" />
    </head>
    
    <body>
    <script type="text/javascript" src="examples/examples.js"></script>
    <h1>XML Grid Example</h1>
    
    <!-- a place holder for the grid. requires the unique id to be passed in the javascript function, and width and height ! -->
    <div id="grid-panel" style="width:600px;height:300px;">
    <div id="example-grid"></div>
    </div>
    </body>
    </html>
    Any sugestions on what I am doing wrong?? Any pointer would really be helpful

    Thanks

Page 2 of 8 FirstFirst 1234 ... LastLast

Similar Threads

  1. Paged Grid Filter Field
    By JeffHowden in forum Community Discussion
    Replies: 38
    Last Post: 1 Jan 2009, 8:59 AM
  2. creating stationary filter row on row0 of grid
    By ianfer in forum Ext 1.x: Help & Discussion
    Replies: 0
    Last Post: 26 Mar 2007, 5:08 AM
  3. Filter the grid
    By Greeens in forum Ext 1.x: Help & Discussion
    Replies: 0
    Last Post: 13 Feb 2007, 11:17 AM
  4. Using Filter()
    By irishdunn in forum Ext 1.x: Help & Discussion
    Replies: 10
    Last Post: 19 Oct 2006, 5:20 AM
  5. Filter and query
    By pje in forum Ext 1.x: Help & Discussion
    Replies: 1
    Last Post: 28 Sep 2006, 9:03 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •