I read the information on the browser history and I understand that I do not have access to the array of history objects, and even more so I can not delete them. However, my task is to exclude the addition of parameterized URLs to history. I have tabs in my project, their URLs:
/profile,
/profile?menu=1
/profile?menu=2
I use nextjs framework in my project. His navigation code:
public handleOnClickItem(key: string) {
const id = '1';
const href = `/profile?id=${id}&menu=${key}`;
Router.push(href, href, { shallow: true });
// tabs are navigated
Router.onBeforeHistoryChange = (url) => {
console.log('App is changing to before history change: ', url);
};
}
Can I not add this url to history? I get it in console.log. And as I understood from the description of the method, this URL should not yet go down in history.
Any ideas? Thanks!
This should solve it:
https://nextjs.org/docs/api-reference/next/router#routerreplace
Similar to the replace prop in next/link, router.replace will prevent adding a new URL entry into the history stack.
Meanwhile keep in mind shallow routing option is used to trigger/not trigger next.js lifecycle methods (eg. getInitialProps) when doing the routing.
Load your contents via AJAX once you're in the website, and do not keep updated URLs.
The downside to this is that your user's wouldn't be able to bookmark a specific page (no permalinks). In history it will only show the base url without parameters only.
There was a similar post here on SO
Related
Is there any way to get the previous URL in JavaScript? Something like this:
alert("previous url is: " + window.history.previous.href);
Is there something like that? Or should I just store it in a cookie? I only need to know so I can do transitions from the previous URL to the current URL without anchors and all that.
document.referrer
in many cases will get you the URL of the last page the user visited, if they got to the current page by clicking a link (versus typing directly into the address bar, or I believe in some cases, by submitting a form?). Specified by DOM Level 2. More here.
window.history allows navigation, but not access to URLs in the session for security and privacy reasons. If more detailed URL history was available, then every site you visit could see all the other sites you'd been to.
If you're dealing with state moving around your own site, then it's possibly less fragile and certainly more useful to use one of the normal session management techniques: cookie data, URL params, or server side session info.
If you want to go to the previous page without knowing the url, you could use the new History api.
history.back(); //Go to the previous page
history.forward(); //Go to the next page in the stack
history.go(index); //Where index could be 1, -1, 56, etc.
But you can't manipulate the content of the history stack on browser that doesn't support the HTML5 History API
For more information see the doc
If you are writing a web app or single page application (SPA) where routing takes place in the app/browser rather than a round-trip to the server, you can do the following:
window.history.pushState({ prevUrl: window.location.href }, null, "/new/path/in/your/app")
Then, in your new route, you can do the following to retrieve the previous URL:
window.history.state.prevUrl // your previous url
document.referrer is not the same as the actual URL in all situations.
I have an application where I need to establish a frameset with 2 frames. One frame is known, the other is the page I am linking from. It would seem that document.referrer would be ideal because you would not have to pass the actual file name to the frameset document.
However, if you later change the bottom frame page and then use history.back() it does not load the original page into the bottom frame, instead it reloads document.referrer and as a result the frameset is gone and you are back to the original starting window.
Took me a little while to understand this. So in the history array, document.referrer is not only a URL, it is apparently the referrer window specification as well. At least, that is the best way I can understand it at this time.
<script type="text/javascript">
document.write(document.referrer);
</script>
document.referrer serves your purpose, but it doesn't work for Internet Explorer versions earlier than IE9.
It will work for other popular browsers, like Chrome, Mozilla, Opera, Safari etc.
If anyone is coming from React-world, I ended up solving my use-case using a combination of history-library, useEffect and localStorage
When user selects new project:
function selectProject(customer_id: string, project_id: string){
const projectUrl = `/customer/${customer_id}/project/${project_id}`
localStorage.setItem("selected-project", projectUrl)
history.push(projectUrl)
}
When user comes back from another website. If there's something in localStorage, send him there.
useEffect(() => {
const projectUrl = localStorage.getItem("selected-project")
if (projectUrl) {
history.push(projectUrl)
}
}, [history])
When user has exited a project, empty localStorage
const selectProject = () => {
localStorage.removeItem("selected-project")
history.push("/")
}
I had the same issue on a SPA Single Page App, the easiest way I solved this issue was with local storage as follows:
I stored the url I needed in local storage
useEffect(() => {
const pathname = window.location.href; //this gives me current Url
localstorage.setItem('pageUrl',JSON.stringify(pathname))
}, []);
On the next screen (or few screens later) I fetched the url can replaced it as follows
useEffect(() => {
const pathname = localstorage.getItem('pageUrl');
return pathname ? JSON.parse(pathname) : ''
window.location.href = pathname; //this takes prevUrl from local storage and sets it
}, []);
Those of you using Node.js and Express can set a session cookie that will remember the current page URL, thus allowing you to check the referrer on the next page load. Here's an example that uses the express-session middleware:
//Add me after the express-session middleware
app.use((req, res, next) => {
req.session.referrer = req.protocol + '://' + req.get('host') + req.originalUrl;
next();
});
You can then check for the existance of a referrer cookie like so:
if ( req.session.referrer ) console.log(req.session.referrer);
Do not assume that a referrer cookie always exists with this method as it will not be available on instances where the previous URL was another website, the session was cleaned or was just created (first-time website load).
Wokaround that work even if document.referrer is empty:
let previousUrl = null;
if(document.referrer){
previousUrl = document.referrer;
sessionStorage.setItem("isTrickApplied",false);
}else{
let isTrickApplied= sessionStorage.getItem("isTrickApplied");
if(isTrickApplied){
previousUrl = sessionStorage.getItem("prev");
sessionStorage.setItem("isTrickApplied",false);
}else{
history.back(); //Go to the previous page
sessionStorage.setItem("prev",window.location.href);
sessionStorage.setItem("isTrickApplied",true);
history.forward(); //Go to the next page in the stack
}
}
I have been working on dynamically generating tvml-templates with very frequently changing content for a tvOS app on Apple TV. Generating the templates works fine, however I have not been able to get the app to update/reload the content of a template when navigating back and forth between views or leaving and reentering the app. Only rebooting seems to reload the tvml template.
Your template will refresh itself automatically whenever you manipulate the TVML within the template document.
If you maintain a reference to the document like so:
var myDoc;
resourceLoader.loadResource(templateURL,
function(resource) {
if (resource) {
myDoc = self.makeDocument(resource);
});
}
you can manipulate the TVML using myDoc and your view will automatically change.
So if your template document includes a "collectionList" and you were to run this code:
//Removes the child elements of the first collectionList
var collectionLists = myDoc.getElementsByTagName("collectionList");
var collectionList = collectionLists.item(0);
while (collectionList.firstChild) {
collectionList.removeChild(collectionList.firstChild);
}
your view would no longer display the UI elements within the collectionList. The view will refresh itself the moment the code is run.
The answer by #shirefriendship pointed my in the right direction (thank you!). As another example, if you wanted to change the text of a single element in a template (such as the description), you would need to use the innerHTML property:
function changeDescription(incomingString) {
console.log("inside the change description function")
if (incomingString) {
var theDescription = myDoc.getElementsByTagName("description").item(0);
theDescription.innerHTML = incomingString;
}
}
This changes the description immediately to the viewer.
If you are using atvjs framework, you can easily create and navigate to dynamic pages which are regenerated while navigating.
ATV.Page.create({
name: 'home',
url: 'path/to/your/api/that/returns/json',
template: your_template_function
});
// navigate to your page
ATV.Navigation.navigate('home');
Set this in the header of your API:
Cache-Control:no-cache
Got it from Apple Docs: https://developer.apple.com/library/tvos/documentation/General/Conceptual/AppleTV_PG/YourFirstAppleTVApp.html
IMPORTANT
When serving JavaScript and XML files from your web server, you often
need to ensure that any changes to your pages are always visible to
the client app. To do this, your server must ensure that the client
does not cache any of the pages. When your server responds to an HTTP
request for a page that should not be cached, the server should
include Cache-Control:no-cache in the HTTP response header.
I have a single page website and would like to achieve the following:
back button working as if it was a normal website
and instead of say,
www.mysite.com/index.php?p=#this-is-a-great-product
I'd like to have this url
www.mysite.com/this-is-a-great-product
while still having back button working properly.
Regarding 1.) I use the following code ive found which works great:
<!-- Getting BackButton to work properly -->
<script type="text/javascript">
var times = 0;
function doclick() {
times++;
}
function doclick() {
times++;
location.hash = times;
}
window.onhashchange = function() {
if (location.hash.length > 0) {
times = parseInt(location.hash.replace('#',''),10);
} else {
times = 0;
}
}
</script>
…but of course it just changes any anchors to /#1, then /#2 and so forth ro get the backbutton to work. But as I'm not a programmer I don't know how to change it… :(
Regarding 2.) i can add in htaccess this:
>RewriteEngine On
>RewriteRule ^([^/.]+)/?$ /index.php?page=$1
and this changes /index.php?p=products to /products.
So how do I change the above code (under 1.) so it doesn't change all anchors to #1, #2, etc. but instead references / uses the urls I achieved under 2, like
www.mysite.com/this-is-a-great-product
And (probably a very dumb question, but a very important one) -given I use only the new url links on my site- is there any danger that this still might result in duplicate content in any way?
Regarding this, should I (for that reason or any other) sefreferential my single page index.php to itself using rel canonical link=index.php?
Thanks so much in advance!
As mentioned, you will want to use the HTML5 History API. Please note, this API is relatively new and therefore browser support is a concern. At the time of writing, approximately 71% of global Internet users have support for it (see http://caniuse.com/#feat=history for browser support information). Therefore, you will want to ensure you have a fall-back solution for this. You will likely want to use the older #! solution that was popular before the HTML 5 History API was adopted.
If you use the history API to replace, for example, example.com/#!settings with example.com/settings and a user bookmarks that nicer URL, then when they go to visit it, their browser will make a request to the server for /settings (which doesn't actually exist in the web server's context). Therefore, you will need to make sure your web server has some redirection rules (i.e. RewriteEngine) such that it can take the pretty URLs and redirect them to the #! version (and then if the user's browser supports the history API it can replace that with the nice URL).
If you aren't very comfortable programming yourself, I'd recommend using a JavaScript library that does a lot of the work for you. I did some quick searching and discovered the following, though there might be better ones out there: https://github.com/browserstate/history.js
Basically i have created a small prototype on jsfiddle which tracks all the urls accessed via ajax calls.
Also contains navigation to access links back and forth .
How It Actually Works:
I have created a global array called history, which keeps track of all urls accessed via ajax in sequence.
also there a global index defined to keep track of the url being accessed when navigating back and forth the links in history array.
There is History section at the bottom of the jsfiddle, which shows the sequence in which the links are accessed by capturing the link names and posting them in the order in which they were accessed.
JS Code:
$(function () {
var history = [];
var index = 0;
$('.links').on('click', function () {
$('#history').append($(this).text());
var address = $(this).attr('data-ref');
index += 1;
history[index] = address;
$('.links').attr('disabled', 'disabled');
loadExternalPage(address);
console.log('list:' + history);
});
$('#back').on('click', function () {
console.log(index);
index -= 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
$('#forward').on('click', function () {
console.log(index);
index += 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
var loadExternalPage = function (address) {
console.log(history[index]);
$('#result-section').load(address, function () {
console.log('data-loaded');
$('.links').removeAttr('disabled');
});
};
});
Live Demo # JSFiddle:http://jsfiddle.net/dreamweiver/dpwmcu0b/8/
Note: This solution is far from being perfect, so dont consider it as final solution but rather use it as a base to build upon
On using BACK and FORWARD functions in the browser top-left button:
In principle, there is no great problem with this as long as you work with the existing storage object (a stack) for previously visited web pages on your browser. This object is the history object and you can see what is in it anytime by right-clicking and selecting "Inspect", then selecting the "Console" tab, then enter window.history and enter.
Check out the Browser Object Model (BOM) section of Pro Java For Web Developers (Frisbee) for the background to the history object. (Just a few pages, an easy read, don't worry.) Just remember that in this process you are storing the new page that you move to, not the old page that you are leaving !
For a simple SPA example, look at this example. codepen.io/tamjk/pen/NWxWOxL
In regard to the URL, the method that the history object uses to load a new page state into the history stack, i.e. pushState(...), has an optional third parameter for associating a dummy URL for each web page that is stored.
Personally, when I first sorted out the BACK & FORWARD functions, I did not use dummy URLs as the browser was being confused by them and I had enough to do sorting out the history sequence using just the first two parameters, i.e.
the state object - a JSON holding enough data to recreate the page stored
a title for the page I expect that you could also use a dummy URL but I will leave that to the student as an exercise, as they say.
But you can add the URL of the new page if you want to.
In the example above, for the state object I just used the IDs of the page's nav link and its content element.
For the title, I programmatically changed the HTML's page title element with each change of page. I did this after noticing that the browser listed the previous pages according to the title element in the HTML code.
Unfortunately, this title does not show up on CodePen when you right-click on the browser BACK and FORWARD buttons due to CodePen's system not allowing it. But it will show on your own sites.
It's important that whatever method you use to store current web page states when using the navbar links to navigate, you DO NOT ADD page states to the browser history when you arrive at them using BACK or FORWARD buttons. Otherwise your history stack will have repetitions of entries going back and deletion of entries going forward.
In the CodePen, this was achieved by having the addToHistory(..) function separate to and outside the scope of the switchPage(...) function. This allows you use of the switchPage function in both normal navbar navigation and browser BACK/FORWARD navigation. The third parameter of switchPage(...) is a boolean indicating if the page is to be stored in history or not.
Anyway, this is just something to get you started.
I have a SammyJS-based single page application running under http://[mydomain]/[myapp]/[subPath]. The server is configured to return the same HTML "startup" page no matter what [subPath] is, i.e. the route is configured with a wildcard for the subpath.
Since I want users to be able to bookmark a particular subpath in the application (e.g., "/orders/123"), I need to force the client to navigate to that subpath once the "startup" page is loaded. What is the best way to do this? I've tried doing window.location.pathname = window.location.pathname after setting up my application, but that just caused an infinite loop of re-navigating to the page.
When creating the SammyJS application, simply pass window.location.pathname to the run() method as follows:
Sammy(function () {
this.get(/* custom route */, function (context) {
// ... handle navigation ...
});
}).run(window.location.pathname); // Voila!
I use this method:
Hashbang URLs using Ember.js
And now i have website with hashbangs. But people come also to old URLs with only hash, but without hashbang.
So how to change URL from only hash to hashbang if someone visits the old style url?
I dont think you need to tweak ember for that. Simple solution is before ember application loads you can run the following code.
var url = window.location.toString();
if(url.split('#!').length==1) {
if(url.split('#').length==2) {
window.location = url.split('#')[0]+'#!' + url.split('#')[1];
}
}
Basically what it does is rewrites the url to #!.
UPDATE: Else one more way is write above code in Ember Initializers.
Here is the jsbin http://emberjs.jsbin.com/aLiretO/1#post