How to cope with refreshing page with JS History API pushState - javascript

A small website I was creating (more like fiddling) uses AJAX to load each page. Previously I was changing the hash of the url, this worked great but was ugly, and the user could refresh the page, and it would stay on the same page.
Now I have switched to using pushState in the JS History API, which looks much better, and the back and forward work, but refreshing does not. For example:
Going to: http://example.com/page2 goes to a 404 as there is no real page called page 2. But if I click on the button which uses the pushState method to change the url, it works as it should.
How can allow refreshes, and permalinks with the new History API?
(And how do search engines treat this, seeing as Google had to create a way of indexing hash urls, by making the developer switch to #!, is it possible they will do something similar for the history api in the future?)

You shouldn't use pushState to push invalid URLs at all. It's meant to be used in cases where the site works both with and without AJAX - i.e. you push the URL which would result in the same output without AJAX when creating this output with AJAX.
If you want only virtual URLs (like in the pre-pushState era), keep using the hash tag.

This is a somewhat old question, but it was one of the top google results. In the pursuit of being helpful, here is my solution.
You can use Apache's Mod_Rewrite to rewrite the url to a central location.
For example:
example.com/p2 gets its page content from example.com/index.php?page=p2
You can keep your current implementation of the History API and AJAX to get the content and include the following in your .htaccess
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^([^/\.]+)/?$ index.php?page=$1&full=1 [L]
</ifModule>
In your index.php:
<?php
if(isset($_GET['full']) {
//Generate the full page here
}else{
//Generate just the content for AJAX
}
?>
This Page is a good primer on using mod_rewrite to redirect an entire website. (Comments 11 & 13 have useful additions as well)

I had to redirect 404 errors to the sites homepage (the one that loads the AJAX requests), and then get the last component of the URL, and run the javascript function that loads the page using an AJAX request. Not a great solution but it seems to work well.

Related

Angular Removed # tags in urls. But not working as expected

I just removed # tag from my url of angular single page app.
I did like.
$locationProvider.html5Mode(true);
And It worked fine.
My problem is when I directly enter any url to the browser it showing a 404 error. And its working fine when I traverse throughout the app through links.
Eg: www.example.com/search
www.example.com/search_result
www.example.com/project_detail?pid=19
All these url's are working fine. But when I directly enter any of the above url's into my browser it showing a 404 error.
Please any thoughts on it.
Thanks in advance.
Well i had a similar problem. The server side implementation included Spring in my case.
Routing on client side ensures that all the url changes are resolved on the client side. However, When you directly enter any such url in the browser, the browser actually goes to the server for retrieving a web page corresponding to the url.
Now in your case, since these are VIRTUAL urls, that are meaningful on the client side, the server throws 404.
You can capture page not found exception at your server side
implementation, and redirect to the default page [route] in your app.
In Spring, we do have handlers for page not found exceptions, so i
guess they'll be available for your server side implementation too.
When using the History API you are saying:
"Here is a new URL. The other JavaScript I have just run has transformed the page into the page you would have got by visiting that URL."
This requires that you write server side code that will build the page in that state for the other URLs. This isn't a trivial thing to do and will usually require a significant amount of work.
However, in exchange for that work you get robustness and performance. When one of those URLs is visited it will:
work even if the JS fails for any reason (such as a dropped network connection or a client (such as a search engine) that doesn't support JS)
load faster than loading the homepage and then transforming it with JS
You need to use rewrite rules. Angular is an single page app, so all your request should go to the same file(index.html). You could do this by creating an .htaccess.
Assuming your main page is index.html.
Something like this (not tested):
RewriteRule ^(.)*$ / [L,QSA]
L flag means that if the rule matches, don't execute the next RewriteRule.
QSA means that the URL query parameters are also passed with the rewrited url.
More info about htaccess: http://httpd.apache.org/docs/2.2/howto/htaccess.html

Change page content according to what URL is used to access your domain

For ex: My website is www.mydomain.com
the only thing on the page is
<h1>Category</h1>
When a user types in the url www.mydomain.com/sports I would like for the page www.mydomain.com to load (with or without the /sports path, preferably keeping the same URL the whole time) and know that the user accessed the page using the url www.mydomain.com/sports to get there.
At which point, I could then use javascript to change
<h1>Category</h1>
to
<h1>Sports</h1>
I am able to redirect the page www.mydomain.com/sports to www.mydomain.com, but when doing this the URL changes and I can't detect the page URL that was used initially to navigate there (www.mydomain.com/sports) using javascript: http://www.w3schools.com/jsref/obj_location.asp since it returns the new page URL without the path.
Am hoping for a non PHP/.htaccess solution.
UPDATE:
I resorted to using htaccess to fix the problem, was easier than expected to implement.
Here's what I used in case someone else finds this useful
.htaccess file (upload to the directory on your site where you want it to be used, in my example, that would be the main directory)
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase / ****start at/find the root directory
RewriteRule ^(/sports|sports/)$ index.html [NC,L] ****find and clear index.html from URL if the extension is mydomain.com/sports or mydomain.com/sports/
</ifModule>
Take a look at this plug-in.
http://html5doctor.com/history-api/
History.js
This plug-in allows you to push a new URL onto the history of the browser (in a cross-browser compatible fashion) without actually refreshing the page.
Therefore your approach would be as follows.
List item
On load, Get the window.location to get the "Sport"
Push the www.mydomain.com onto the history stack (using history.js)
Change the h1 to "Sport".
The only issue with this approach is that if someone tries to bookmark the page, it will not be the content that they encountered the last time they navigated to the URL. This however may be the point of what you're proposing in your question.
Your server-side code should use add a setCookie header having the value of the category that you want to display. Then your javascript code can get the cookie and set the field appropriately.

How can history.pushstate allow a single point of entry for nested url paths

Sorry for the badly worded question.
PHP with apache uses index.php/index.html for directory urls like:
localhost = localhost/index.php or localhost/place = localhost/place/index.php
If I start with:
localhost/place
and I use a javascript history.pushstate to update a url with a long adress like:
localhost/place/subplace
then if I enter that url in the browser I'll go to localhost/place/subplace/index.php when I really wanted localhost/place/index.php to allow that url to be the only point of entry.
I'm using simple javascript(window.location.pathname or anchorNode.pathname) to retrieve the url path for use with ajax. This is used by a simple router similar to backbone.js to update the page. The javascript routing works and back/forward in the browser works. If only I could get it to work with the single point of entry for urls entered in the address bar.
To sum up:
I want a single point of entry for my php app to get all subdirectories.
At the single point of entry I want to run the javascript to acquire the path and use it to route the page with ajax.
I'm using history.pushState to update the url, but that messes with the single point of entry for the app when the directories are longer than the main directory. Basically I get a 404 page.
Right now I'm not too concerned with making it backwards compatible with browsers that don't have history.pushState. I just want this one thing to work.
As an addendum I would prefer working with regular paths in javascript and not the query string. Whether the page is loaded with the address bar or the history.pushState is used that's what I would prefer. I don't know if this can be handled with apache rewrite or what.
Similar questions:
How to cope with refreshing page with JS History API pushState
Ok. I'm making things too hard.
To get the routing to work on page load I need to do two things.
In the .htaccess file I can use apache rewrite to make all urls route to index.php?path=first/second/third.
When the page loads just concatenate the the new path in the query string to the javascript string that handles the route.
The javascript is still being used, and there's no duplication of functionality. Everything is good.
This also kind of answers this: How to cope with refreshing page with JS History API pushState

History.js - sharing link of a AJAX loaded page

I have the following function that activates when I click on some links:
function showPage(page) {
var History = window.History;
History.pushState(null,null,page);
$("#post-content").load(page + ".php");
}
The content of the page updates, the URL changes. However I know I'm surely doing something wrong. For example when I refresh the page, it gives me the Page Not Found error, plus the link of the new page can't be shared, just because of the same reason.
Is there any way to resolve this?
It sounds like you're not routing your dynamic URLs to your main app. Unless page refers to a physical file on your server, you need to be doing some URL rewriting server-side if you want those URLs to work for anything other than simply being placeholders in your browser history. If you don't want to mess with the server side, you'll need to use another strategy, like hacking the URL with hashes. That way the server is still always serving your main app page, and then the app page reads the URL add-on stuff to decide what needs to be rendered dynamically.
You need to stop depending on JavaScript to build the pages.
The server has to be able to construct them itself.
You can then progressively enhance with JavaScript (pushState + Ajax) to transform the previous page into the destination page without reloading all the shared content.
Your problem is that you've done the "enhance" bit before building the foundations.

Will google index the correct URL for hashbang/escaped_fragment content

I have recently read Google's Making AJAX Applications Crawlable as I was wondering how to correctly prepare my dynamic site, which uses hashbang navigation, for SEO.
I understand now that for mysite.com/#!/foobar I should serve an equivalent html snapshot at mysite.com/?_escaped_fragment_=foobar.
I just want to know if google then correctly indexes my page as http://example.com/#!/foobar
or if it uses this escaped_fragment url? I'm assuming (but would like to be sure) it will correctly use my hashbang url for the search results but that the indexed content was taken from the escaped_fragment page.
Some confirmation would help me sleep better. thanks
By default, google will create escaped_fragment url for your page. That could end up looking ugly.
You should redirect escaped_fragment url to a page page with a prettier url using 301
Say your server gets a URL request from googlebot/any hashbang compliant crawler such as "targetPage?_escaped_fragment_=command=play%26id=4ee7af"
You should have your targetPage accepts targetPage?_escaped_fragment_= .... and created a 301 redirect to itself as "targetPage?command=play&id=4ee7af" ( or any other pretty url as long as it is to the same page)
If you were using J2EE you could create a servlet filter to intercept and 301 redirect to cleaner url of the same page.

Categories

Resources