How to achieve state persistance on tab reload? - javascript

Simplified Use case
I have a working single page web app called data_store. This app has 2 simple tasks list
List users
Show user details (when a user is clicked).
Now for this, I have 2 routes
data_store/all_user
data_store/user_detail
*For the sake of simplicity, all other factors can be ignored.
Problem: When I reload the tab my at data_store/user_detail, I loose on the unique ID of the user whose details were to be shown.
Question: How can I persist the unique ID on tab reload? and make it work seamlessly across duplicated tabs?
Failed Solutions
1st, use data_store/user_detail/<UUID> format but I cannot expose it in my URL for security reasons.
2nd, use local_storage to store current UUID, but then the reload of other tabs with different user's details breaks.
Reason: as they pick up the last set value by any other tab also.
3rd, use session_storage but the problem is that while duplicating tabs instead of opening a new one. The chrome to duplicate a tab uses the window.open and generates a daughter tab that shares all the info from its parent, including sessionStorage.

I think you can put the user's crypted identifier in the URL, If you encryption is based on a seed then it should be possible to encrypt/decrypt it, and make it unavailable for some basic hacker.
I have found this thread refering to a low level of encryption, maybe it can help you.
For a Higher encryption level, crypto-js could be a solution.
Now, if you don't want parameters in your url and don't need to support IE < edge 14, maybe you can try to get the tab id and store your data with it, so on reload it will be easy to associate data with tabs. I don't know its behavior with tab duplication tho.

Related

Is it possible to get a tab (or window) identifier that stays the same across page reloads?

Question:
Is there an api or way to determine some kind of an id/uuid of the current tab/window the page is displayed in that is stable when the page is refreshed?
To give you more context why this is important to me:
My use case is to allow my single page app (SPA) to be opened in multiple tabs at the same time.
Right now I can't do it because while the current state is persisted in a "currentModel" property in localStorage, unfortunately not all urls of the SPA are "self-contained" . By "self-contained" I mean that the url itself should be sufficient to reload that state from the backend (or localStorage) because it contains some kind of id/uuid (this flaw of my SPA has grown historically and I know it's not what HTML was meant to be used, however as there's a team of 60+ developers working on that SPA you can imagine that this cannot be refactored in a single day).
So what I have are some urls like this "/search" that display a search form, but also information about the current context (i.e. think business object).
Now if I want to allow the SPA to be opened simultaneously in multiple tabs, I can no longer use a simple "currentModel" property. Instead I need to make it a hashmap with the keys being tab/window ids so that the context of a tab can be restored in case the user hits F5/refresh in one of the tabs. Of course this id whatsoever would need to be stable across page reloads.
Workarounds that I know of
Writing a custom browser extension that has access to tabs
Updating the url to include a "tab"-id created when the SPA is bootstrapped
The window.name property (at least in modern Firefox and Chrome) maintains its value across an F5 page reload. Thus, code can check window.name for navigational hints or whatever else might be useful in order for it to "get its bearings" in the absence of information in the URL itself.
Thus, a newly-loaded tab will be able to detect that it is in fact newly loaded, and can insert and update the name property of the window whenever it wants. Upon a reload, code can sniff the name and request additional stuff from the server (or do whatever) if it sees that sort of information already present in the window name.
I have been able to put any sort of string into that property, in quite limited tests, but it's possible IE is picky about the name having to have some particular form (like a valid identifier or something).
You may still be able to leverage localStorage but instead of keeping one object representing your state, maybe you should keep state on a route-by-route basis?
const state = {
"/": { state: {} },
"/page-2": { state: {} }
}
// persist state
localStorage.setItem('state', JSON.stringify(state))
// unwrap state for route /
const routeState = (JSON.parse(localStorage.getItem('state')))['/']
You can try leveraging the window.onbeforeunload action to save state for a page when a user refreshes the page. You could do something like:
window.onbeforeunload = function(event) {
localStorage.setItem('lastState', JSON.stringify(state))
}
And then when a page reloads, check if state exists in localStorage, load it, and remove it. This method assumes that users won't be reloading pages and opening new ones at the same time. Otherwise, you'd need some other identifier when saving the state which puts you back in your original predicament.

Forward redirect to previous page

I have a webpage which is linked to from a number of different webpages, a user clicks a link on one of the parent pages, arrives at the webpage and completes a task. When the task is complete the user needs to be redirected to the previous page.
I'm aware I could use the window.history.back() / window.history.go(-1) functions - however what i'd really like is something which the browser considers a 'forward' action so as not to confuse the users if they click the forward/back button after a redirect.
I've tried using document.referrer but this gets blanked in the event of a page reload on the webpage.
The solution would need to be compatible back to IE8 (unfortunately!). Any suggestions would be much appreciated.
Fetching referrer URLs can be unreliable no matter which language you use https://stackoverflow.com/determining-referer-in-php
The best option is to pass the parent url to the task along with the data that you are already sending, despite the initial time outlay (updating the parent pages to do this) it would be the most reliable.
You could try and do a similar thing with a session or cookie to store the url upon starting the task, but it depends on how you have written the current task as to wether you would still need to modify the parent pages.
What about providing a parameter (it may be even the whole url to go after the action) that will let the page know where to go? (like login pages usually do).
It will probably imply modifying all your pages, so it may not be a solution in your case.

Cross Domain Conversion Tracking

SETUP:
Having a few different information sites/domains about my products and one single site/domain shop-site where you the purchase, checkout and so on happens, I'm having troubles to find a proper solution for a comprehensive tracking of all the pages including the conversion tracking.
IDEAL:
What I want is to get reports seperated for each site (shop-site as well as information-sites), but add some conversion tracking. Ideal would be to be able to track a conversion when the user gets to the checkout process, so that I can see it in the statistics of the shop-site as well as on the site that referred to this sale/conversion and maybe even a funnel visualisation for the whole action.
WHAT I ALREADY GOT:
I already set up statistics for each site/domain. I do have set events for a referal to the shop-site as well as an event when the user checks out.
WHAT I TRIED:
I set up cross domain tracking for one of my information-sites and the shop-site, so now the events show up in that single property.
Unfortunately thats not the statistic I intend to get, as the whole data got consolidated from those 2 properties. Also it made the tracking goal/conversion only accessible for that single property, while I can't distinguish between a conversion made originally from this site or one of the others.
Is it possible to achieve what I actually intend to do or what's the proper way to track such a setup??
You can either use an additional tracker (so you have one UA id that goes in your "normal" domain, one that goes in your shpooing site and one that is placed on both sites) - you'd still have both pages tracked in separate properties, but you'd have one rollup property that tracks all your sites. This might however unwanted complexity if you use event tracking etc (since you'd have to see to it that events are always pushed to the correct tracker).
An easier solutions is via views/profiles - use the same UA id for both sites; create views based on domain name (filter in the admin section) to track each site separately; for the common data view that display data from both sites create a filter that includes the hostname in the reports so you can tell both sites apart in the report.

How to Stop Sitecatalyst Visit Tracking Increment for particular web App

I have a page “Googlesapp_welcome” is showing up in the my home page report suite and accounting for ~10000 visits per month. I know this is necessary to enable the tracking of the registration process. But what is the best way to remove it from reporting? Is it to change the sitecatalyst code on this page to not increment a visit? Is it just to filter it out of our reporting.
(But I have to keep in mind with all reporting in the future prospective)
If you want to completely stop that page from being tracked, ie no beacon will be sent to Adobe, you can set "s.abort = true". Create a function after you set your s_account variable that matches the URL you want to filter and sets s.abort = true. Keep in mind, this will really mess up your referring data as the next page view will see an internal referral as the first page view on the visit. If you are using multi-suite tagging, you will lose all beacons to all report suites.
If I were you, I would create a segment that excludes page views or visits on that page from the report suite and look at the data that way. Or, if you just don't want to see the traffic that is bouncing, create your segment excluding and single page visits that entered on that page.
Aborting the pixel is a drastic step and should be very well thought out before employing that tactic.
Use VISTA rules to accomplish the desired result.

(Temp) Storage of JSON Search Results in Web App

I'm working on a search function for my Web app (HTML, JS & CSS only). I'm using jQuery's .getjson() method to retrieve data from a feed and display those results on a page. Inside of an .each() statement I'm adding HTML markup to the results making some of the elements links to outside sources.
The issue is when a visitor initiates a search on my Web app and clicks on a link from the results to an outside page, then uses the Back button on the browser to go back to the results page, all of the search results are cleared and another search needs to be initiated.
I'd like to temporarily save the search results so if a user clicks on a link from the results, then presses the Back button to come back to the app, all of the results will be available without the new for another search.
Taking this one step further, it would also be cool is the results for past searchs also persists so if the visitor continues to press the Back button, they can see all of their previous searches (with a given limit of course).
HTML5 sessionStorage seems to be ideal for this, but the information that I found points to a tedious coding solution. Can't I just save all of the json results as a JS object and have them re-rendered by my each statement when the visitor presses the Back button? I'm definitely open to using a code library or plugin for this problem.
http://brian.io/lawnchair/ is a good little library for API for persistence. You can use the same syntax as an abstraction for different storage options http://brian.io/lawnchair/adapters/
You have two ways to approach this issue, one is caching the results on your server and populating the view on-demand, and number two is like you previously mentioned - use sessionStorage. sessionStorage (IMO) has a very straightforward API. You can either use sessionStorage.setItem(key, value) or sessionStorage.getItem(key) -- other methods are available as well such as sessionStorage.key(index), sessionStorage.removeItem(key) and sessionStorage.clear(). It would probably be useful to include a cross-browser polyfill solution for sessionStorage, you can check out the "Web Storage" polyfills section at Modernizr: https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills -- Have fun :-/
Off the top of my head:
Every time the user searches, change the hash in the url to a unique string (e.g. 'search-{userInput}' ... you could of course just forget about the 'search-', but I like my urls in pretty). This should give you back-button support. Then:
Alternative A:
Listen for the hashChange Event, parse the window.location.hash and resend the request to your search URL. Theoretically, unless adding the timestamp to the URL or crazy stuff like that, the caching mechanism of your browser should kick in here. If not, it means an additional request, but that should be ok, shouldn't it?
Alternative B:
Extend your existing search query mechanism by caching the results to localStorage (just don't forget to JSON.stringify it beforehand and use a something-{timestamp} key). Then listen for the hashChange Event and pull the results from your localStorage. Personally, I wouldn't recommend this solution as you're clogging up the localStorage (afaik there's a limit at 2.5mB for some browsers).
You're probably going to have to find ways to circumvent missing browser support for at least the hashChange Event, JSON stringify/parse and LocalStorage, but I'm optimistic that there are enough libs/plugins out there by now.
You think too complicated: your search form most likely does not change the url! Use GET instead of POST and you have the desired result. Right now the browser has no way of knowing which state of the website you want to show and by default shows the first - the empty search form
Caching could be added as suggested, but that really is not the problem here

Categories

Resources