Page-Refresh in a SPA with HTML5 Browser History API? - javascript

Instead of using hash URLs for my SinglePageApplication I would like to use the HTML5 Browser History API. This works fine so far (I'm using emberjs).
The pro of the hash URL is, I can refresh the page without worrying about the result. When I try to reload with the browser history API I'll get a 404 (since my server don't have a route for this).
So: Is there a common workaround to avoid this behaviour?
I could tell my server to redirect to the index page but this wouldn't show me the correct content.
Example:
GET host/#images
... shows the "images" page (even when it is the index.html)
GET host/images
... redirect to host/
... shows me the content of the index template

Is https://stackoverflow.com/a/17288940/1423583 an answer to your question? Basically it says that you have to change the server to always serve the index.html page.

Related

Handling Dynamic Routes Without a Server

Is it possible to serve a dynamic html page without a backend server or without using a front-end framework like Angular?
Edit
To clarify, the index file is served from a backend. This question is about how to handling routing between the index and dynamic pages.
I have an application that consists of two files - index.html and dynamic.html. When the user clicks an option say "Option A", they are served dynamic.html and the url is updated to /option-a. Now, with a server this is no problem and assuming the user visits the app from the landing page, it isn't a problem either because a cookie can be set. However, suppose a user visits a page at my-domain/option-a. That route doesn't exist and there is no server to redirect so it will 404. They would have to visit dynamic.html.
I think this architecture demands that there's either a server to handle route redirects or a SPA framework.
Is there something I'm missing?
your SPA framework will be active only once your HTML page is loaded and to do that you need to redirect any URL that user tries for your domain to that HTML file. For this you obviously need a server (and since you are talking about my-domain/option-a I assume you have atleast a basic server). You can refer to this link to get an idea on how server can redirect a URL to specific html file: Nodejs - Redirect url.
Once HTML is loaded you can initialize your SPA framework and decide the template to be loaded based on the URL.
Note: without a server you will access URLs using file://somepath/index.html and anything other than this URL will result in 404 and no SPA framework can handle that.
I think the solution is to use a static site generator such as Jekyll or Middleman and allows you to convert information into static pages. That way you functionally are building a bunch of pages but they are all compiled ahead of time. You can add dynamic content that is loaded in from a yaml file and it will compile the content into separate html pages.
It is not possible, but there is a workaround using url parameters like this:
my-folder/index.html
my-folder/index.html?=about
my-folder/index.html?=about/sublevel
my-folder/index.html?=profile
my-folder/index.html?=./games
const urlParams = new URLSearchParams(location.search);
const route = urlParams.get('');
console.log(route);
// Should print "about" "about/sublevel" "profile" "./games"
Of course this approach is not as clean as using a server for routing, but it's the best you can get without a server.
BTW. I tried an alternative solution creating symlinks with all the target routes pointing to the same index.htmlfile. But it did not work because the browser (firefox) redirects by default when it finds a symlink, thus home is shown all the time.

The different behavior between Link and Anchor tag in React-router

I think it is a convention to use Link over Anchor tag. From my understanding, Link tag will be translated into anchor tag into html. However, from my observation, Link will render the page in the client side and also cache the page, the anchor tag will render the page in the server side.
Here is the code, I have one component which has method willTransitionTo
willTransitionTo: function (transition, params, query, callback) {
console.log('transition to');
}
When I have another component to link this component, if I am using Link from react-router, the log will be printed in the browser console. The interesting thing is that it cached the data on the second time when I link to this page (no data fetched from the network). On the other hand, the log will be printed in the server side console if I am using anchor.
I understand what anchor does, but I dont understand why anchor in the Link is client side rendering. Is it an expected behavior ? Also, how Link know how to cache the data if I dont misunderstand.
Many thanks in advance
I'm unsure exactly what you're asking. I think what you're asking is why the URL in the browser changes without it generating a new HTTP request. The reason is HTML5 history.
HTML5 history allows us to have nice URLs in front-end routing instead of the old style hash based URLs, i.e. /page instead of /#page. In this sense, React Router is nothing more than a wrapper around HTML5 history.
When using HTML5 history, it's important to make sure the back end is configured to serve up the pages at all your routes. e.g. You can have a front-end transition from / to /cart, but if you then reload the page you'll get a server error if your server hasn't been configured to serve the endpoint /cart. This is also important for older browsers (e.g. IE9) that don't support HTML5 history, which will gracefully degrade to traditional HTTP requests.
For more on HTML5 history, there's the always readable CSS Tricks.
https://css-tricks.com/using-the-html5-history-api/

replicate google maps URL behaviour with javascript? url+"/#foo"

google map does this thing where if I browse to, say, Australia, the URL changes to
https://www.google.com/maps/#-28.0345854,135.1500838,4z
I'm interested in doing something like this on my web application. So far I have this:
var baseurl = window.location.href.split("/#")[0]
window.history.replaceState( {} , 'foo', baseurl+'/#foo' );
which works just fine for adding "/#foo" to the url
My problem is that, after adding /#foo, the URL doesn't work, it 404es.
I'm not interested in modifying the brower's history, that's why I use replaceState instead of pushState.
anyway, is there a way to do this with js? or do I need server-side code to serve the appropriate page?
thankyou
You "need server-side code to serve the appropriate page". an # character is still part of the URL and therefore needs to be handled by the server. If you want to handle the this kind of situation client side only then what you want is to use # instead. anything after a hash is handle client side and does not trigger a new page to load from the server.
Several libraries use this to replicate routing in a single page HTML only app. For example:
Backbone.js Router
jQuery-Router
jquerymobile-router
Ember.Router
And many more.

using 404 page for ajax fallback?

I want to make a single page website, that uses history.pushstate to change the url.
I can make my site have only one html file, the 404 page. so that no matter what url people enter, they get to that page.
My question is: Is there a drawback to abusing 404 pages in that way?
Does google care?
Are there browser quirks?
A better solution is to just have all URLs other than / answer with a permanent redirect to /. You should in any case never actually return the 404 status code because at least some versions of IE will display its own error page instead of whatever HTML you send back.

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.

Categories

Resources