Is there an event like hashchange for query strings? - javascript

I have been using hashes to pass data between pages (like setting scrollTop(), etc.) and have also used the hashChange event to trigger changes on a given page.
However, hashes have default behaviors that I'm not necessarily interested in, like making the page jump to a given (sometimes insignificant) spot.
I feel like getting/setting a query string would be more logical, but:
Is it?
Is there an event I can listen for when the query string is set?
Are there query-string-related behaviors I should know about?

It depends on what you're doing.
A query string change will always trigger a page reload. The only part of the URL you can change without a page reload is the #-part.
In javascript applications, page loads are generally not okay. But it may be possible to use when having a traditional html page request/response model.
There's no event AFAIK though, since it will change page.

As the other answer says, changing the query string will cause a page reload. As far as the browser is concerned you'll then be on a completely new page.
There are events that will fire when you do this. The ’beforeunload` event will fire, however it won't be very useful as it also fires when the user clicks on a link or closes the window.
Effectively the event that will fire if you change the query string will be the load event on the new page that it loads.

It is illogical to reinvent anchor behaviour. It is better to not expose hash links to insignificant fragments (although modern browsers are doing scrollIntoView() for any element with id, there is a dedicated behaviour for <a name="xxx">). So, answer is yes here, page arguments should be passed via querystring.
Event is window.beforeunload, yes, page reload when javascript:void(location.search='some') has been set
There are no surprises, have a look
Also, on working with querystring: http://xkr.us/js/querystring

Related

Google tag manager single page app get element on history change

I have created a few variables for custom dimension on pageviews.
Pageview trigger: windowload or history change
The data is being pushed through, but it's only getting previous pages'
for example,
page/1 div class "page date" is 25th Jul, I would get undefined, but
when I click onto page/2, i would get the page/1's "page date"
function() {
return window.document.getElementsByClassName('page date')[0].innerText;
}
It seems that the history event is triggered before the corresponding page content is loaded into the DOM. This is nothing you can blame GTM for (GTM sees a history change, inspects the DOM, and grabs whatever it finds there, and that's the normal/expected behaviour).
Your solutions:
Make sure content is updated in DOM BEFORE the history event is triggered: this is something to sort out on the application side, and that may not be easily changed (if you use a framework like react it's probably best if you don't start hacking its core behaviour).
Delay the history event triggers: have a look at this solution which describes how to achieve this. Please note that solutions based on delays are never 100% reliable because there's a race condition between your delay and the loading of content, and you don't know for sure who will come first (and increasing the delay too much can cause the side effect of users changing pages in quick successions before analytics had a change to capture them).
Detect DOM changes: a more robust alternative would be to monitor the DOM for a particular element that is unique to each page (eg a <meta> element with the page ID or URL). You could use a tag to initiate the monitoring of this element when you receive the history change, and when the element actually changes it means the DOM has been updated, and you could fire your own trigger. This could be done via the MutationObserver or using a setInterval/setTimeout loop to check manually. However if the DOM is changed in several phases (blocks by blocks) this would not work (your <meta> element would have changed but not the div you're looking for), requiring you to start monitoring on a per-element or per-block level, which will be quite some work.
Push a dataLayer from your application: this would be my preferred option. I would hook into the logic of your application (you should be able to extend the routing method or the app framework should give you event listeners you can bind a custom function of yours with in which you can tell GTM that the page has been changed (eg dataLayer.push({'event': 'page_changed'});)

Change div class onclick --- and *save* the change

There are many questions that ask how to change the class of a div in a JavaScript click handler, e.g., here: Change Div style onclick. I understand that well (just change .className), and it works.
However, when I follow a link from my page to somewhere else, and then click the back button, the class names are reverted. (Safari and Firefox get it right, Chrome does not.) In Chrome, most other changes I make dynamically, e.g., to click handlers, are also reverted when I go back to the page (although it remembers freshly inserted new divs).
Note that neither Chrome nor the other browsers are reloading the page when I press "back"; they must just take it from the cache. (I update the state on the server using ajax, so it works fine when the browsers reload the page.)
I am not really a web developer, so this is a bit puzzling. What is the standard practice here? Should I use history.replaceState() every time I change the divs? Should I save the changes in a state variable and reload them every time there is a popstate event? Instead of changing div classnames, should I delete the div and insert a fresh one (with all the old div's children)?
I am using vanilla JavaScript here (no jquery even) and would prefer to keep it that way if possible.
It is possible, but you will need additional ways to remember it
You could try one of these:
Cookies: This definitely looks like the best way to go
Pass Vars on the URL: example: www.mywebsite.com?myvar=red. This would be easier using PHP, but still is possible in pure JS (but I don't recommend it)
Store it on Database: (don't recommend this at all)
Store it in input elements: In current browsers, input element values (of radio buttons, hidden, etc.), persist after POST-ing, and returning using the back button.
These are just some options, but I don't recommend using them for what you want (it is a waste of time and effort if you weight the Pros and Cons of what you want to do)
You can save state in cookies and restore it when page loaded.
Also you can save it on server-side (send state using ajax, when it changed). And send prepared document to client when it requested again.
Browser forget all states when you reload page.

Beatport new interface

Beatports new interface has solved a major problem I was looking for the solution too.
Namely, it keeps a "player" interface at the moment and you can browser to different parts of the site (also changing the url) without reloading or interrupting the player.
I cannot for the life of me understand how they have done this, can any of you guys figure it out?!
Many thanks for any replies I get
Looks like they are just using AJAX to load new content but have taken care to make it work and look pretty seamless. You can get better insight into what events are attached to what elements via the Visual Events bookmarklet. Once you find the code that triggers the event, you can run the obfuscated javascript through JSBeautifier to examine it more closely.
Specifically, it looks like they're adding click handlers to all anchor tags, passing off the event if it was triggered with a middle click or modified with a keyboard key, otherwise passing it to a dynamic loader which handles state and other specific conditions like multiple clicks. The seamlessness of it comes from the way they deal with URLs making every page bookmarkable and the browser history so the back and forward buttons work as you would expect on a "normal" site.

Changing the URL with jQuery without reloading the page

How do I change the URL with jQuery without reloading the page?
Set location.hash
jQuery has nothing to do with it though, this is basic DOM 0.
You can only change the hash part of an url without a page refresh through location.hash.
Adding get parameters (?foo=bar) or a complete url change will always reload the page.
In HTML5 you get more options to change URL's, but right now (2010) it's not yet viable since crappy browser die out hard.
In general, leaving aside the new HTML history API, you can't.
It is possible to add data to the URL after the hash (using location.hash as David Dorward describes). However, if you want to do this to affect behaviour of the page, you will also need to read these changes via jQuery (or triggered by the same process that sets the hash.)
Outside of the History API you will not be able to add a parameter, and have the page 'just know about it'.

Assigning to document.location.href without clobbering history

In testing document.location.href, I have observed that when the user initiates an action that results in javascript that assigns to document.location.href, the new URL is added to the history.
However, if the call is initiated by javascript that is result of, say, state change of an XMLHTTPRequest, the entry for the current page in the history is over-written. Have I characterized this correctly? Is there a way to get the page change to be reflected in the history in this latter case?
I was facing the same problem and found this workaround which worked for me
instead of
function onAjaxCallback(evt){
location.href=newLocation;
}
i wrapped the location.href call around a setTimeout. Seems to do the trick. My history's behaving fine now. Hope that helps
function onAjaxCallback(evt){
setTimeout(function(){
location.href=newLocation;
},0)
}
You could change the location without having the browser display a Back button like this:
window.location.replace(new_url);
However, the original address remains in the browser's history and may be accessed using something like CTRL+H
Reference:
https://developer.mozilla.org/en/DOM/window.location#replace
https://developer.mozilla.org/En/DOM/Window.history#Notes
study: window.location.replace() and window.location.assign()
URL can be manually added to history before redirecting the user.
if (window.history) {
history.pushState({}, window.location.href);
}
window.location.replace("/login/?next=" + window.location.pathname);
Read the original question more carefully. The question is not about content loaded by an XHR, but about content loaded by a script loaded by an XHR. I had the same problem and the setTimeout method seems to work well.
Alas, your question can't be answered, AJAX requests have nothing to do with browser history, and if you loaded some dynamic content with them, then the user clicked the browser back button, the previous page is loaded (this which was loaded with an ordinary GET or POST request), which corrupts the sequence you display content in.
Dmitri's answers means that you will maintain your own history for the dynamic content using the fragment part of the url (this after the # symbol), maybe you'll provide your own back and forward buttons, but still you're not protected from the effect of the browser back and forward buttons.
If only they had provided some kind of events to handle user clicks on these buttons with the ability to cancel.

Categories