Improve clientside components

It would be very cool if components like CGridView could provide more possibilities on the client side. As yii already depends on jQuery, it should maybe get a little closer to jQuery UI standards:

1. Use methods in jQuery UI style

Instead of ugly looking calls like $.fn.yiiGridView.update(id,options), it would be more in a jQuery UI style to write:


 $('#my-grid').yiiGridView('update',options);

or




var sel=$('#my-grid').yiiGridView('getSelection');



2. Bind to events on clientside

Currently event handlers have to be configured on the server side. That means we have to write javascript that should be executed e.g. afterAjaxUpdate in our views. I would find it much more flexible to provide jQuery events, that you can easily connect to from clientside. For example:


$('#my-grid').bind('gridviewselectionchanged',function(selection){ ... });

The current implementation already comes pretty close to a "usual" jQuery plugin. I think it would not take much to change it to the above style. What do you guys think?

I agree, the current JQuery ‘wrapper’ approach is just another thing to learn.

I agree with Mike

As I do most of the times, you should implement your plugins using jquery ui widget factory or create a widget factory based on it.

It is a great start point that will help you develop the plugins faster and better

It resembles structured programming, that uses namespaces, public and private properties, inheritance, a constructor and a destructor method, public and private methods, events and more.

The down side is that you must include ui.widget.js with it, altho, its acceptable (3k uncompressed, 1k compressed)

What do you think ?

@Gustavo: I like this idea. We should reuse what is out there and the UI widget factory seems to provide a solid foundation for writing custom plugins.

Speaking of client side components, before redesign the new grid, take a look at the built-in grid that will come with jQuery UI 1.9

http://wiki.jqueryui.com/w/page/47182351/Grid-Widget

Looks great

Btw, JUI 1.9 will have a lot of changes and new features, like tooltip, menu, grid and more.

Actually this "pattern" is a jQuery preferred way for creating plugins - http://docs.jquery.com/Plugins/Authoring#Plugin_Methods

I will try to implement this with the current code and keep the BC for now…

Mike do you have some ideas on how to implement the #2 (client side events)?

When the current code is refactored to match one of the proposed patterns above, it should become pretty straightforward to add jQuery.trigger() calls at the apropriate places and add useful extraParams to each call there. That’s all you need to do to provide events from a jQuery plugin.

About BC: Personally i think this is not a good idea to keep BC, as the current interface is not really in line with how jQuery plugins are meant to be used. I would consider the $.fn.* an internal namespace which should only be used by plugin developers. If you want to keep BC (and all $.fn.* calls) you can’t use the example plugin pattern (the last one on the page you provided) anymore. At least not without changes again.

Yii 2.0 will break some BC anyway. To me the clientside "plugins" are those components where this makes most sense. The interface will become cleaner and we even have more possibilites in JS.

BTW apart from gridview i find the activeform one of the most important components that should be refactored. It’s probably one of the most frequently used and thus should leave no wishes open. It should provide way more control to set and get attributes, trigger validation, set and get errors, bind events, etc.

Yes, in Yii 2.0 there is no need for BC… my idea was to make the change now… not to wait for Yii 2.0… that’s why I wrote “… current code and keep BC for now”

this way users can get used to the new Yii JS pattern while the old code will still work…

Actually I already have a working copy… just testing it…

I commited the first revision… can you help testing it

http://code.google.com/p/yii/source/detail?r=3443

All "old" code should work… and now the "new" style can be used… like


$('gridID').yiiGridView('update');

$('gridID').yiiGridView('getRow',3);



Cool, thanks. I hope i find some time to test it.

Thank you… just check that you get the latest version… as I’m fixing things as I find them… :D

I had a look and it seems to work fine. And it’s much cleaner code IMHO :).

Some things i noticed:

  • selectCeckedRows somehow doesn’t really fit well into the clean names of other methods. I think there should be a ‘setSelection’ method instead. Then the in selectCheckedRows (wich should be private) this method could be used instead

  • Instead of using a custom pseudo-event mechanism, why don’t we use jQuery’s built in event system? Then if e.g. ‘beforeAjaxUpate’ is set, it should just attach it as a handler for e.g. ‘yiiGridViewBeforeAjaxUpdate’ in the init method. And trigger this event where beforeAjaxUpdate was called before. This would allow to bind events purely form clientside code.

Thank you for testing…

You are right selectCheckedRows is used only internally no need for it to be public… but I did not understand your comment as getSelection() is already there… like the getChecked()

for now the idea is to maintain the code totally BC compatible… so that we do not break current users code… but at the same time to get users used to the new format that will be used from now on (yii 2.0)…

I agree for the events… will try to find a way to implement them by keeping the "pseudo-events" too…

getSelectoin() is there - but not setSelection(). :)

Sorry… I still don’t get it…

Here is the getSelection() - http://code.google.com/p/yii/source/browse/trunk/framework/zii/widgets/assets/gridview/jquery.yiigridview.js#279

getSelection is a getter, i talk about a setter :). We should not only have a method to read out current selection, we should also allow to set the current selected rows from outside. Then instead of having public ‘selectCheckedRows’ you could implement the private method like this:




function _selectCheckedRows() {

    // ... obtain ids of current checked rows here ... then:

    methods.setSelection(ids);

}



Inside setSelection you can also deal with the update of the select-all checkbox. Maybe also allow to supress update of Checkboxes at all with another parameter: setSelection(ids, updateCheckboxes). If updateCheckboxes is true (default), then the checkbox status is also updated.

Got it this time… .did not notice the “get” just the misspell “selectoin” and was wondering where that was :D

selectCheckedBoxes is used to preCheck those checkboxes that has a value in the table… for example if you use an attribute from the database… if the value of that attribute is not 0… the checkbox will be checked… this is used only when the grid is refreshed…

I dont see the point in having the setSelection() / setChecked() (note that we have two separate functionality - selecting the row and selecting the checkbox) as this is done by clicking the row / checkbox…

I think setSelection() could be very useful. Consider not only having a “select all” option on top, but also a select by status, like “select all open”, “select all closed”, … It’s exactly methods like these that i’m missing from most of the yii components: I want to be able to interact much more with them from javascript. So why hide these options and not provide a very flexible interface to the user? We should make the clientside components as open and flexible as the server side ones.

It’s not only making the clientside open… it’s about connecting it to the backend (PHP / database)…

Can you elaborate a bit more on this…

how would you call setSelection() in the case of "select all open"… what would you send as a parameter… (array with: rowID/status or rowNumber/staus pairs)… how woudl you get those information to be sent as parameter?

one problem to consider is that if pagination is used… the checkbox status is not "remembered" and refreshed from scrach on every page change (selectCheckedRows)

setSelection should accept an array of keys - that’s all. Just as counterpart to getSelection, which returns these keys. Then i can write my own javascript to filter the right ids. This of course would require another method “getKeys” which returns all ids of current rows in the grid.