RRListView - a CListView extension to allow Ajax browser history

I’ve created an extension (but hesitate to call it such, since it is only really a few small modifications of CListView and its associated Javascript file, which is why I’m putting it here rather than upload it as a proper extension), to allow browser history while navigating the pages of a ListView using Ajax.

This is handy for user navigation, but also for things like users copying and pasting links to their friends (using this system their friends should see what they saw using that link, rather than automatically the first page of the ListView that they were on).

All you need to do to use it is download it and put it in your extensions directory (there is a text file included with instructions), then use it instead of the CListView widget and everything should be taken care of automatically.

I’ve changed as little as possible in both the CListView class and the jquery.yiilistview.js file. So in CListView I have overridden only the init (which still calls the parent init method) and registerClientScript methods. And in jquery.yiilistview.js, I have simply changed the initial configuration of the object, and used the hashchange event to initiate Ajax loads, with the pager buttons simply changing the hash - the Ajax load itself has not been changed at all. Hopefully this should maintain as much compatibility as possible, although I have not tested any Ajax sorting etc to see if it is affected.

Please feel free to let me know about any problems or changes that should be made.

I Uploaded the wrong (dev) version of the files please do not use them.

This is the correct version of the files:

Hello,

This script is exactly what i was looking for

I’ve just installed it (the second link) but the problem is that is not working :

Whith this script it’s doing the same thing that if i have desactived the javascript… with this in the url

myApplication/index.php/user/index?Location_page=2

And reload the entire page…

Did i do something wrong ?

Thank you

Manu

Ok, I’ve changed this to take into account other Ajax variables, so hopefully it shouldn’t interfere with any other things using the hash link, and should take into account other things as well as pagination.

I have also made a similar version of the CGridView widget, although it doesn’t yet support filtering, so I will upload that later.

Hello!

I’ve justed uploaded another (better) version. Please give that a try and see if it works.

Otherwise, can you give me some details about what is going wrong, and how you are using it?

I see that you’re not using Url rewriting (myApplication/user/index?Location_page=2 rather than myApplication/index.php/user/index?Location_page=2) - I don’t think that should cause a problem, but I haven’t tested it without Url rewriting. Have you emptied your assets folder so that you’re sure the JS file is published? Have you seen if there are any console error messages in Firebug?

It is hard for me to give any cause just like that, but the best thing is certainly to look in the Firebug console to see if anything is popping up, or just to examine your Ajax requests to see if they are coming back properly.

Let me know if you find anything/need anything else.

Rupert

Red Rabbit Studio

Hello thank you for your answer.

I’ve installed the new one and still the same problem.

When i go to my location page (which contain a list of cities), it display 700 000 results.

localhost/web/index.php/location/ (sorry i bad copy/past in the older post)

1. When i use this code :

<?php $this->widget(‘zii.widgets.CListView’, array(

'dataProvider'=&gt;&#036;dataProvider,


'itemView'=&gt;'_view',

)); ?>

–> when i go the page 2, the page isn’t reloaded, the data are reloded in ajax, nothing change in the url. I access to the page 2 but i can’t go back with browser history.

2. When i use your code :

I copy all your files in the "extension" folder so it looks like :

"extensions/RRListView/RRListView.php" and "extentions/RRListView/RRListView/jquery.rr.yiilistview.js" files.

In the config main i have :

'import'=&gt;array(


	'application.models.*',


	'application.components.*',


	'application.extensions.*',


),

And in my location view file (instead of zii.widgets.CListView) :

<?php $this->widget(‘ext.RRListView.RRListView’, array(

'dataProvider'=&gt;&#036;dataProvider,


'itemView'=&gt;'_view',

)); ?>

These are the only things i did.

And when i access to the page "localhost/web/index.php/location/" it show the first page, wich is great but when i access to the page 2, it reload the entire page, show the page 2, and it change the url to "localhost/web/index.php/location/index?Location_page=2" instead of "#page=2" (maybe… ?)

(the exactly same thing than zii.widgets.CListView WITHOUT javascript one the client --> for safety)

So nothing happened in Firebug… no js error, nos ajax call…

I am new to the yiiFramework… sorry if i misunderstood something.

Thank you for your share and your time man,

Manu

Sorry i kind of find the error… when i run firefub i was still in "javascript off mode" … so now i can see where the error is.

I’ve cleared all the asset and run the page.

the error is that the site try to find this js :

localhost/koople/web/assets/3ccf49a9/jquery.rr.yiilistview.js

But it’;s not here but here :

localhost/koople/web/assets/3ccf49a9/RRListView/jquery.rr.yiilistview.js

Did i do something wrong in the parameters in my previous post?

I tried to manually moove the &quot;jquery.rr.yiilistview.js&quot; to this location "localhost/koople/web/assets/3ccf49a9/jquery.rr.yiilistview.js" and the script is working well (#Location_page=7)…

I thinks i’m close the my goal

Thank you if you know what i did wrong

Manu

Hi - I didn’t know we had limits on posts… - never mind.

I made a version of the JQuery extension with lots of console.logs to help you with debugging (attached below), but given what you’ve just said, I think the problem is simply where you unzipped the files - on my system, the directory structure in the compressed file is maintained - ie the RRListView.php file is in the extensions folder, then there is the sub-folder RRListView in the same extensions folder which contains the jquery.rr.yiilistview.js file (and where you should copy the files from /framework/zii/widgets/assets/listview, apart from jquery.yiilistview.js, in order to use the same images and things as with the original), so the RRListView.php folder should be in the extensions root, and the Javascript file in the RRListView sub-folder, not both in the same (we don’t want to publish the RRListView.php file as part of the assets).

So, to solve, simply delete the RRListView files you put there already, then unzip the compressed file directly in the extensions folder so that it puts the files in the right place:

extensions/RRListView.php

extensions/RRListView/jquery.rr.yiilistview.js

extensions/RRListView/[all the other CListView asset files]

If you want to use the (primitive) debugging version of the JQuery extension, simply unzip and copy the attached file over the extensions/RRListView/jquery.rr.yiilistview.js file - just remember to copy the original over it again when finished, because the debug uses "console.log", which will cause error in IE.

Hope everything works for you with this - let me know if not.

The limit is just for new users…

as there was to many SPAM "attacks" on this forum and the dev team could not be constantly online, we had to add some automatic SPAM preventions…

One of that is that a new registered user can post only 3 times on his first day, so that his posts (if SPAM) can be reviewed by the dev team…

Ok, thanks for the info.

I did like you said :

extensions/RRListView.php

extensions/RRListView/jquery.rr.yiilistview.js

extensions/RRListView/[all the other CListView asset files]

And it’s all working well, nice extension, very usefull!

Thank you ! :)

Manu

Glad it helped!

I’m actually working on a couple of things like this right now - like I said, I’ve also done a version of the CGridView widget (but haven’t yet implemented the filter part), and I’ve been doing other Ajax stuff such as automatic authorization redirection on timeouts etc, which I’ll try to make available when I’ve done.

Ok, here’s the latest (yet again improved) version.

There is an extension for both CListView and CGridView, and full hash history should be maintained for all pagination, filtering and sorting events. The actual hash monitoring logic is in a separate Javascript file (jquery.rr.hashhandling.js) which can also be used to attach hash history monitoring for other Ajax events of your own making (I’ll give more details on that later). If there is an Ajax error, there is an error handler which allows us to revert the hash to its previous state.

Once again, I advise you to copy the original CListView and CGridView assets into the assets folders of each of these extensions, in order to maintain the original look.

I have tested reasonably on my system and everything seems to work, however, I have not tested in different browsers (like IE) or different systems. Please let me know if you come across any bugs or have any cleaner ways of doing things.

Enjoy!

Hi i just came over this thread and tested your extension. Because I also wanted some feature to keep the sort + searchoptions on the gridview when using the browser back buttons.

Every thing is working BUT I find it quite strange.

If i access my page via this url disseminations/admin (dissminations is my controller, admin the action) I get the full gridview rendered.

If i then click a column to sort an ajax request is been done (disseminations/admin?sort=dissemination_type.desc&ajax=disseminations-grid) and the browser url is changed to disseminations/admin#sort=dissemination_type.desc. Through the ajax the gridview is beening sorted correctly.

So far so good. If I access the changed browser url (disseminations/admin#sort=dissemination_type.desc) in a new tab the normal gridview is been rendered through the admin action of the controller with the default sorting and an ajax done on pageload which requests the gridview again but this time sorted of the requested column.

So i have 2 times to render the gridview (one through the url request and one through the ajax load) and only the second one is showing the wanted results.

It comes even worse if i then have a filter set and reload / open the generated url in a new tab there where 2 ajax requests been done. So there a 3 requests where 2 requests aren’t show the correct results.

Is this normal? and if not what is wrong with my code? It would be very helpfull if you can upload some demo e.g. for the blog demo. Because currently I have no clue what could be wrong.

BTW i used the latest version you attached.

Hello!

I’m glad you’ve found it useful.

Yes, it is normal that you have multiple ajax loads if you access the hashed link in a new tab - as far as I know, the server will never be sent the hash part of the url (which is for links on the page only), so it can have no knowledge of the state given by the hash. Therefore it sends the normal page given by the url before the hash then, once loaded, the javascript kicks in, generates a hashchange event so that the hash part is checked, and then makes the appropriate ajax requests if it detects that the state given by the hash is not the same as the one given by the url before the hash.

This is therefore a necessary overhead (and you’ll find the same for any other javascript browser history plugins, unless they load everything on the one page and then hide it - in which case it is not true ajax anyway), and retains its utility on the basis that you will only have this overhead if you are using the link with hash from a fresh start - when using back and forward buttons it will not be an issue.

As for the extra ajax requests beyond the initial one, this is due to the fact that you can bind as many ajax handlers as you like, and the changes that they make to the page do not necessarily have to correspond to ajax requests to the base page, or correspond to the same options for that page. Therefore I don’t see any simple way to aggregate requests to the same page into one request without losing the independence between the different handlers.

So, it sounds like you are doing everything right, and the results you are getting are to be expected (I assume the pages are functioning as you want).

I must warn you that I haven’t had time to check the latest versions of the jquery.yiiGridView.js file and update mine appropriately so, although I think it should still work with the latest version, I don’t actually know.

Let me know if you have any more questions.

Thx for answer,

I guess i found some issue. I added the extension to the blog demo from yii and used the filter search.

With the normal gridview and search for the title="test post" i would find my post entry with "test post" in the title.

With your extension it will search for "test+post", this is also added as the filter value.

the ajax request url is wrong when a filter has some "spaces" used

With your extension:

/post/admin?Post[title]=test%2Bpost&Post[status]=&Post_page=1&ajax=yw0

with the normal grid

/post/admin?Post[title]=test+post&Post[status]=&ajax=yw0

the + seems to be escaped in the ajax request. Or the bbq url generation is, because when i change the hash url from

post/admin#Post[title]=test+post

to

post/admin#Post[title]=test%20post it will show the correct results.

Ok, thanks - that does sound like an issue. I’ll have a look at it when I get some time.

I had some time and tried some different approach, and implemented it directly in the jquery.yiigridview.js file.

And it works ;)

I limited the additional ajax request to only one which has to be done when a url with bbq url’s is pasted into a new browser window.

I tested also multiple gridview’s on one page as well as filter changes.

So far I can’t find no problems/bugs.

Currently the bqq usage for ajax requests is enabled by default. It can be changed via the settings which needs a public property in CGridview (need to be extended).

For testing just replace the original file in the asset folder.

rename the file to from .js.txt => .js (attachment was permitted).

Remarks are Welcome

regards Horizons

Ok, that’s good if it works for you.

The reason I had originally separated the hash handling from the gridview was so that other widgets or functions could also use the hash in the same way without having to have a hashchange handler for each one. In my logic a widget could initiate a hash change, and also pass a callback to be fired if needed (if one of its parameters were concerned), so that if a change in the hash happened which did not concern that particular widget we wouldn’t have to fire multiple hash change events anyway, and we wouldn’t have to duplicate code in checking whether the change concerned the widget.

If you try my modification it is exactly what you mean modifications in the #yw0 part of the url would make changes to the #yw0 widget only.

Just add 2 gridviews on the same page and test it out.