Implementing push state manually

Hi, i don’t know if this is the right place to post this since i feel this a really vague and generic question (not specific to the framework really) but i haven’t been able to find a good explanation anywhere else.

I’m trying to implement push state (history API) on my project to allow the user to keep to browser back/forward button functionality without the use of pjax (pjax doesn’t work too well in some cases in my project so i’ve switched to normal ajax and trying to do push state by myself now).

For now, i’m modifying push state everytime i do a succesful ajax request. I’ve been able to succesfully reload the pages by manipulating the onpopstate event like this:

window.onpopstate = function() {

$("#section-content").load(window.location.href);

}

But there are some problems with “reloading” some pages this way (mainly pages with dynamic content generated, like dynamic inputs and fields, these inputs dissapear since they don’t exist when the page gets rendered). Also i’ve noticed that the page reload is significantly slower compared to using pjax.

There are mainly two problems that i can’t figure out how to solve right now. First, how can i deal with pages with dynamic content so when pressing the browser back/forward button the page gets rendered just how it was before the user navigated somewhere else? and finally, how can i reload the page “faster”?

I know the way i’m doing it right now is probably not the best, but i don’t know how it can be done in a better way.

Any help is highly appreciated.

I’m starting to understand things a bit better now, but i’m still having trouble with some parts. I’ve changed the window.onpopstate handler to just replace the html content from a previous state like this:


window.onpopstate = function() {

$("#section-content").html(history.state.container);

}

This "reloads" the previous page (at least creates the effect of reloading the page) that i store in history.pushState(state, null, url), so basically in every ajax call i store the html of the current page like this:


var state {container: htmlOfCurrentPage, name: name, page: currentPageUrl}; 

Every time the back/forward button is pressed i modify the html of the page with the previous one from history.state.container. This works as i expected, except when there are select2 widgets in the previous page. For some reason, the widget gets “rendered” like it should when there’s no option selected, but if it has any option selected, the widget doesn’t get rendered (just a normal text input with the selected option in it).

I’ve tried to reload the select2 manually after back/forward button is pressed, but it still gets rendered wrong.

Again, any help is highly appreciated.

I believe you need to remove the old select2 from the dom. You may have to initialize them again after you destroy them.

To destroy them you would call




jQuery('select').select2('destroy');



I personally use barba js to manage pjax when i use yii2 and it works well for me. It also has a cool prefecthing feature function too. Here is the front end of a yii2 site that I have used it on and it has pretty fast page transition times because of it.

Using the push state method definitely makes a huge difference on load times when done correctly. [size=2]It’s a lot of work to get this to work correctly no matter which way you go but it’s [/size]definitely[size=2] worth the inital headache. [/size]

Thanks a lot for your answer skworden.

You were right, i had to “remove” the old select2 from the dom when I reload the page, i’m currently using this inline script to do it:




<?php $this->registerJs("$('.select2').remove();", \yii\web\View::POS_END); ?>



I’ve managed to reload every page much faster now by modifying the html of the page when back/forward button is pressed. The only problem is when the user apply some filters in a gridview the values of the inputs doesn’t “re-apply” after back/forward button is pressed, for now i’m manually applying them back to the form. I’ll definitely take a look to barba.js, looks like it can help a lot improving loading times.

It takes some time understanding how to use push state properly but it’s worth the effort for sure. Any help/guidance is highly appreciated.

Glad it worked for you. If you allow the filter get requests to change the url it should reapply them when you go back and forward as each filter would technically be a different url.

If you don’t want the url to change on every filter maybe you could temporarily store the get parameters (I’d use local storage) then when you detect a page change add the current url with get parameters to the history. Doing something like that could reduce unnecessary request of hitting a page then resending another request to filter.