PDA

View Full Version : Dual Example : Add a second tbar to make GridPanel alphabetical search


peter.riche
01-29-2008, 12:13 PM
Hi all,

And as my first message in here, I do thank ALL the team and EACH user contributing. It's a real pleasure to see what a wonderful work can be done within here. =D>

Now, here is my first kind of contribution. I came to the need of a "standard" GridPanel with quite usual "add, delete" buttons to manage a list of people. But I wasn't satisfied with the "paging" system because when I'm searching for somebody in the list (read "the grid"), I'm used to click on his name's first letter as in an address book. So I decided to put all the letters in the top toolbar where I thought it would be great! Here is what I did, first creating the "alphaTbar" items :

var alphaTbarItems = new Array();
for(var i = 65; i < 91; i++) { // JS char codes from (upper) A to Z
var myChar = String.fromCharCode(i); // get the letter from the char code
alphaTbarItems.push({ // add this vars to the array
text: myChar, // just the letter
id: 'alphaTbarItem' + myChar, // this button id will contain the letter
enableToggle: true, // only one will be pressed
toggleGroup: 'alphaTbarItems',
handler: function() { // when this button is pressed
if (this.pressed) { // if it is now in a "pressed" state (toggle is enabled)
myDataStore.load({ // reload the dataStore
params: { letter: this.text, } // passing the letter as parameter
});
} else myDataStore.load(); // if it is unpressed, reload the dataStore with full list
}
});
}

Then here is the GridPanel :


var myListGrid = new Ext.grid.GridPanel({
border: false,
store: myDataStore,
columns: [
{header: 'Name', width: 140, sortable: true, dataIndex: 'name'},
{header: 'Zip', width: 35, sortable: true, dataIndex: 'zip'},
{header: 'City', width: 90, sortable: true, dataIndex: 'city'},
{header: 'Phone', width: 50, sortable: true, dataIndex: 'phone'},
],
viewConfig: { forceFit: true, },
// only one toolbar can be passed inline
tbar: myActionButtonsTopToolbar, // this one has add/delete/refresh buttons
bbar: myInfoBottomToolbar,
});


Then, two things are needed : showing the GridPanel (mine is in a window) and loading the dataStore :

myWindow.show();
myDataStore.load();
myAlphaTbar = new Ext.Toolbar({
renderTo: myListGrid.tbar, // that one line did the job!!
items: myAlphaTbarItems, // use formerly created buttons
});
myListGrid.syncSize(); // don't do that and the toolbar may not appear!


I've modified it "live" for the forum, but that should work like that :

http://img252.imageshack.us/img252/492/notitlepl3.png

Some notes :

myWindow needs an minWidth of ~500 or buttons are masked without any possibility to click them : it probably won't be difficult to add a ">" menu when size is too small (even if I'm unsure how), enlarging "size" problem raising with some kind of "fit" placement when the window is bigger (actually for now buttons stay in place on the left and won't move)
upper/lower case are ignored (read "will work well") by using the following MySQL where clause to handle the letter parameter passed"WHERE SUBSTRING(people.name FROM 1 FOR 1) = '".$_POST["letter"]."'"
the GridPanel will put the "lowercase starting" names (should not exist with names! but you could have the problem for something else) sorted but after the (also sorted) "uppercase starting" names until you add the " type: 'string' " to the "name" field of your data.Record
if one says "I would prefer in a tab style!" I would answer "I won't do it for you" or even "read more about the cls config option for the Ext.Button in the API and do some CSS"


See you!

violinista
01-29-2008, 01:55 PM
Great idea, great work!

Maybe to put one " ", "-", " " separator between letters, only for visual improvement? Just an idea!

Priet
01-30-2008, 02:26 AM
WHERE SUBSTRING(people.name FROM 1 FOR 1) = " . $_POST["letter"]

You should escape this $_POST parameters, as it is NOT safe to use it like this.
WHERE SUBSTRING(people.name FROM 1 FOR 1) = " . mysql_real_escape($_POST["letter"])

peter.riche
01-30-2008, 03:09 AM
Yeah, of course!
Thanks for adding it, and attention to all users : these were test examples !! Please assume your own code security!

vlados
01-30-2008, 03:12 AM
It should be

"WHERE people.name like " . mysql_real_escape($_POST["letter"]) ."%";

becouse if it post "A" mysql will not return the results with "a"

DigitalSkyline
01-31-2008, 08:30 AM
Thx! I used your function to create the a-z toolbar...(much cleaner then creating each button as I was doing) . I'd suggest an (A-Z) button to list all.

Just a side note you have some trailing commas that will cause this not to work in IE.

peter.riche
02-03-2008, 02:36 PM
I'd suggest an (A-Z) button to list all.
Buttons are toggle enabled : unpress the pressed one and the full A-Z listing appear in the grid! Besides, in my app, "Refresh" button do unpress all buttons and show the full A-Z listing :). For those interested, here's how it unpress each button :
for(var i = 65; i < 91; i++) { // unpress the pressed alphaTbarItem toggle Button
var myChar = String.fromCharCode(i); // get the char (from A to Z)
var cmp = Ext.getCmp('alphaTbarItem' + myChar); // get the component under that name
if (cmp.pressed) cmp.toggle(); // if it's pressed, toggles (unpress) it!
}
But I'm sure you could add this A-Z button with no pain! Actually, my PHP function do add the "letter WHERE clause" only if $_POST["letter"] is not empty. So in this case, you'd just alphaTbarItems.push another item with text: 'A-Z' and params: { letter: '' } OUTSIDE of the for loop (before or after, depending of the placement wanted!).

Just a side note you have some trailing commas that will cause this not to work in IE.
I was not told about that "trailing commas" issue in IE! Have you please got some reference for me to read? Or just some further info? Thanks.

thejoker101
02-03-2008, 03:16 PM
Buttons are toggle enabled : unpress the pressed one and the full A-Z listing appear in the grid! Besides, in my app, "Refresh" button do unpress all buttons and show the full A-Z listing :). For those interested, here's how it unpress each button :
for(var i = 65; i < 91; i++) { // unpress the pressed alphaTbarItem toggle Button
var myChar = String.fromCharCode(i); // get the char (from A to Z)
var cmp = Ext.getCmp('alphaTbarItem' + myChar); // get the component under that name
if (cmp.pressed) cmp.toggle(); // if it's pressed, toggles (unpress) it!
}But I'm sure you could add this A-Z button with no pain! Actually, my PHP function do add the "letter WHERE clause" only if $_POST["letter"] is not empty. So in this case, you'd just alphaTbarItems.push another item with text: 'A-Z' and params: { letter: '' } OUTSIDE of the for loop (before or after, depending of the placement wanted!).


I was not told about that "trailing commas" issue in IE! Have you please got some reference for me to read? Or just some further info? Thanks.

There's really no further info on trailing commas, it will just throw an error in IE because IE expects something after the comma. So after you're done setting up an object, make sure you don't have a comma before the end.

peter.riche
02-03-2008, 03:26 PM
thank you! ;)

peter.riche
02-04-2008, 01:15 AM
For those interested, I've just found some readings, start here :
http://extjs.com/learn/Ext_FAQ#My_code_does_not_work_in_Internet_Explorer.2C_but_it_works_fine_in_Firefox

Thanks to JSLint (http://www.jslint.com/), all the fun stuff works well in IE now, and many more code improvements :D

Somewhere, among the gods, Crockford plays with JS!...

mjlecomte
02-09-2008, 07:08 PM
This looks nice, thanks for sharing.

As to the minimum width issue with some 'buttons' getting clipped/masked: Maybe that bar could be made scrollable like the tab panels are (if you have too many then the left and right pointers let you scroll among them).

nathanblogs
08-03-2009, 04:02 AM
Thanks for this,

I also added an additional button 'other' which will deal with all non alpha characters.

The query in MySQL is:


WHERE Left(field, 1) REGEXP '^[^a-z]+$';

steffenk
08-04-2009, 06:20 PM
hi.

thanks for the example and the idea.

"WHERE SUBSTRING(people.name FROM 1 FOR 1) = '".$_POST["letter"]."'"
never do that, it's easy to inject your sql. Golden rule: never trust any input, so never use $_POST or $_GET in your query. In this case use only first char:
$letter = $_POST['letter'] ? substr($_POST['letter'], 0, 1) : '';

to use 0-9 i mostly use sending 0
instead of WHERE SUBSTRING(people.name FROM 1 FOR 1) i use something like

SELECT ORD(SUBSTRING(UPPER(people.name), 1, 1)) ...

and then you can make a switch

if ($letter) {
$ord = ord($letter);
if ($ord > 64 && $ord < 91) {
$where = 'ORD(SUBSTRING(UPPER(people.name), 1, 1)) = "' . $ord . '"';
} else {
$where = 'ORD(SUBSTRING(UPPER(people.name), 1, 1)) BETWEEN 48 AND 57';
}
}

Julio Betta
11-15-2009, 09:28 PM
i'm using a grid with pagination.. how can I do to keep alphabetical search when I use the pagination buttons?:s

Julio Betta
11-16-2009, 06:39 AM
ok. got it...

var alphabeticalTbar = function(store,limit){
alphaTbarItems = new Array();
for(var i = 64; i < 91; i++) { // JS char codes from (upper) 0-9 - A to Z
var myChar = String.fromCharCode(i); // get the letter from the char code
alphaTbarItems.push({ // add this vars to the array
cls:'alphaTbarBtn',
text: i==64 ? '0-9' : myChar , // if index = 64 numbers, else just the letter
id: 'alphaTbarItem' + myChar, // this button id will contain the letter
enableToggle: true, // only one will be pressed
toggleGroup: 'alphaTbarItems',
handler: function() { // when this button is pressed
if (this.pressed) { // if it is now in a "pressed" state (toggle is enabled)
//insert the paramater right into the store
store.setBaseParam('index_search',i==64 ? 0 : this.text);
store.load({ // reload the dataStore
params: {
//index_search: i==64 ? 0 : this.text,
start:limit ? 0 : false,
limit:limit ? limit : false
} // passing the letter as parameter
});
} else {
// if it is unpressed, reload the dataStore with full list
store.setBaseParam('index_search',false);
store.load({params:{start:0,limit:limit,query:'',index_search:false}});
}
}
});
}
return alphaTbarItems;
};
now using in the toolbar


//this is the grid's toolbar
... {
xtype:'toolbar',
//here, I send 2 parameters to the alphabeticalTbar
// 1. the store that the toolbar is gonna handle
// 2. the total limit of the pagination
items:alphabeticalTbar(data.store,25)
} ...the PHP side


$alpha_search = '';
if ($this->object->index_search){
$ord = ord($this->object->index_search);
if ($ord > 64 && $ord < 91)
$alpha_search = ' AND ORD(SUBSTRING(UPPER(descricao), 1, 1)) = "' . $ord . '" ';
else
$alpha_search = ' AND ORD(SUBSTRING(UPPER(descricao), 1, 1)) NOT BETWEEN 64 AND 91 ';
}
//then include $alpha_search in the query...
its working perfectly for me. ;)