AJAX script change navigation on response - javascript

I have a simple search application in which I'm trying to use AJAX in order to navigate to different responses.
My problem is pretty straight forward and I'm sure that there is a simple solution to it but I am simply not able to find it.
I'm sending a new request this way:
xhrObj.open('post', 'search.do', false);
xhrObj.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhrObj.send('id=1');
I would like that, after this request call and the necessary business logic, the browser change the view to the new page specified in the back-end.
Instead of this, I'm receiving the page HTML code in the response but the navigation to this page never takes place.
I was under the impression that if the async parameter is set to false the flow would behave the way I was expecting.
How can I make my JS script to jump it's navigation to the a new page after an AJAX call. Please have in mind that I cannot use location.href to jump to the new page because this new page is a .JSP build on the server.

Maybe you should request for a url from the search.do then do this.
xhrObj.onreadystatechange=function() {
if (xhrObj.readyState==4 && xhrObj.status==200)
{
window.location=xhrObj.responseText;
}
}
hope this helps.

If you want to have something similar what guthub has, you need HTML5 History API. Without HTML5 History API you can't manipulate URL (with help JS) without making any redirection.
Generally you could use hash in url (domain/#hash/blabla/bla) but it's not good also.

Related

window.location.href vs history.pushState - which to use?

I've been teaching myself react-router, and now I'm wondering which method should be used for going to another page.
According to this post (Programmatically navigate using react router), you can go to another page by this.props.history.push('/some/path').
Honestly, however, I'm not quite sure about the differences between window.location.href and history.pushState.
As far as I understand, window.location.href = "/blah/blah"; leads you to anther page by making a new HTTP call, which refreshes the browser.
On the other hand, what history.pushState (and this.props.history.push('/some/path')) does is to push a state. This, apprently, changes HTTP referrer and consequently updates XMLHttpRequest.
Here is an excerpt from mozila's documentation...
Using history.pushState() changes the referrer that gets used in the HTTP header for XMLHttpRequest objects created after you change the state.
To me, it sounds like both methods make a new HTTP call. If so, what are the differences?
Any advice will be appreciated.
PS
I thought that developers would need to consider whether it's necessary to get data from the server, before deciding how to go to another page.
If you need to retrieve data from the server, window.location.href would
be fine, since you'll make a new HTTP call. However, if you are using <HashRouter>, or you want to avoid refreshing you page for the sake of speed, what would be a good approach?
This question led me to make this post.
history.pushstate does not make a new HTTP call (from mozilla doc quoted by you):
Note that the browser won't attempt to load this URL after a call to pushState(), but it might attempt to load the URL later, for instance after the user restarts the browser.
window.location.href = "url" navigates the browser to new location, so it does make a new http request. Note: exception is the case when you specify new url as hash fragment. Then window is just scrolled to corresponding anchor
You can check both running them from devTools console having Network tab open. Be sure to enable "preserve log" option. Network tab lists all new http requests.
You can test this in the Network of your console. When using history with react router, no refresh is made within the app (no http request). You'd use this for a better UX flow and persistence of state. To my understanding, we're essentially modifying the url (without the http request) and react router uses pattern matching to render components according to this programmatic change.
I use browserHistory in react-router v3. There is no refresh and the application state is maintained throughout.
To redirect, all I do is just browserHistory.push('\componentPath'), componentPath which is mapped in the routes config of the application.
So far had no issues , works like charm.
Hope this help.

Dynamic web page with no reloading

I've just recently discovered slack.com and I fell in love with the way they handle their interface. If you've never used it before it's quite easy:
There is a side navbar and an main container on the right. Everytime you click an item in the side navbar it's content is loaded in the container. The focused item changes, the container's content changes, but the page doesn't reload.
If the data changes in the meantime it is magically updated.
What would it take to achieve something like that?
URL changing, page not reloading
Content always up to date
I've been looking at meteorjs in the past few days but the url part is never mentionned.
Yes. Slack is awesome. We (My team) use it everyday. I use it so regularly, at some point I don't check email but I check slack.
So, up to your question.
URL changing, page not reloading
It can be easily done by javascript [ Tl;dr ]
Code:
window.history.pushState("object or string", "Title", "/new-url");
Content always up to date
Well this can be done in two way,
i. via Ajax and Javascript
ii. via socket
i. via Ajax and Javascript:
in javascript you can make setTimeout function to fire ajax request in some duration. via Ajax it will get newest message from backend and it will be shown.
ii. via socket:
in socket, in your case if you use node.js there is a very popular library named socket.io which will get and update message in real time.
Good luck!
You need Ajax. You can use it in conjunction with a script, probably PHP that checks the state of the databse over a timer interval (a "heartbeat") and if anything has changed you load in the new data. I'd recommend having a specific column for a datetimestamp to compare with to make the smallest possible load on your database from this as a lot of users being on the page at the same time will make a lot of requests.
For the "url changing feature but no reload", I think #Kavan Pancholi answered your question. Another way to achieve that is by using the yield templates feature of iron-router.
You are using meteor, it means that you can do it without too much trouble (forget about Ajax & Sockets).
I don't know Slack (but I'll definitely have a look at it) but from what I understand, all data is preloaded/lazy loaded and they only change the displayed elements. In other terms, you keep ready and loaded all your client subscriptions or you bring them up when your yield template is loaded.
I will have a look at Slack and edit this if I realize I did not understood correctly what you are aiming for.
Edit Ok I tried it. You need to use yield templates with iron-router and they also added some transitions effect you can achieve with _uihooks + a loading template
On top of that, if you use a framework like angular, you'll notice urls like this:
http://localhost:3000/#/chat/room
You've probably seen similar with wikipedia in having urls like this:
https://en.wikipedia.org/wiki/Cat#Cats_and_humans
That little # won't reload the page on the url, so you can use that to make a url routing action without changing the page. You can access it with window.location.hash. So on the wikipedia article, you'd get
> window.location.hash
#Cats_and_humans
Combine that with ajax and event listeners and you can do something similar.
// using jquery
// set a callback when the hash changes
$(window).on('hashchange', function (e) {
e.preventDefault();
var hash = window.location.hash;
// get your container where you want to add data and clear it out
var $container = $('#container');
$container.html('<ul></ul>');
if (hash === '#/movies') {
// request json from an endpoint, and with the data, append it to the dom
$.getJSON('/api/movies', function (data) {
data.each(function (el) {
$container.append('<li>' + el.name + '</li>');
});
});
}
});

History.pushState and page refresh

I started looking at HTML5 new history API
However, I have one question. How can one handles the page refresh?
For example a user clicks a link, which is handled by a js function, which
asynchronously loads the content of the page
changes the URL with history.pushState()
The the user refreshes the page, but the URL of course does not exist on the server
How do you handle situations like this? With the hash solution there was no issue there
Thanks
This does require the server-side support. The ideal use of .pushState is to allow URLs from JavaScript applications to be handled intelligently by the server.
This could be either by re-serving the same JavaScript application, and letting it inspect window.location, or by rendering the content at that URL on the server as you would for a normal web application. The specifics obviously vary depending on what you're doing.
You need to perform server side redirection for copy and pasted fake URLs
It all depends on what server side technology you're using. There is no JavaScript way but writing a crazy function in your 404 page that redirect user based on incoming URL that is not a good solution.
The the user refreshes the page, but the URL of course does not exist
on the server
What do you mean by this? I have a feeling your assumption is wrong.
Actually yes, the point is it is the developer who should provide (serverside or clientside) implementation of url-to-pagestate correspondence.
If, once again, I've get the question right.
If you are using ASP.NET MVC on your server, you can add the following to your RegisterRoutes function:
routes.MapRoute(
name: "Default",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" }
);
This will send all requests to Index action of your HomeController and your UI will handle the actual route.
For people looking for a JS-only solution, use the popstate event on window. Please see MDN - popstate for full details, but essentially this event is passed the state object you gave to pushState or replaceState. You can access this object like event.state and use it's data to determine what to do, ie show an AJAX portion of a page.
I'm not sure if this was unavailable in 2011 but this is available in all modern browsers (IE10+), now.

changing window.location without triggering refresh

I have an AJAX form that submits GET requests. Because these are all GET requests these should be easily bookmark-able. Preferably I'd make my Ajax request, update the screen and then update window.location.href to be the URL for the new page.
Unfortunately this reloads the page. Is there any way I can get around this? Basically I'd like the URL bar to be a permalink bar, but it needs to be able to change to keep up with the state of the page.
window.location.hash is no good because that doesn't get sent to the server.
window.history.replaceState( {} , title, new_URL );
This will update the current page URL with a new one without refreshing.
Arguments:
Data object (must be one that could be serialized to text)
The new title of the changed window URL
The URL to change to (without refreshing)
The you could use the window.onpopstate = function(event){...} to listen to events when a user goes back or forward in the browser history and change things however you wish.
The hash is the way to go. Because, as you point out, changes to the hash don't get sent to the server, you have to send an async request to the server as well as updating the hash.
As a simple example, if your URL is http://server.com/page?id=4, when the user triggers the action you send an AJAX request for http://server.com/page?id=4, and set the page URL to http://server.com/page#id=4.
Furthermore, you have to have something to restore the state if the user reloads. This would usually be done by reading the hash value client-side and sending an async request to the server based on the state represented by the hash value.
if you want to do which works in current browser, you can't change window.location.href without reloading the page
your only option is to to change window.location.hash.
you can do that each time you make an ajax call. if you're using jquery, you can bind a function which update the hash each time an ajax call is made.
if you choose that you'll have to look for the hash on page load (actually don't know/think you can do that server side) and make that call to have your page on the state corresponding to the hash.
-- update
there is now an API which provide this functionality look for history.pushState, history.replaceState and window.onpopstate : https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history#Adding_and_modifying_history_entries
it's not availlable everywhere yet ( http://caniuse.com/#feat=history ), there is a few polyfill that you can use for the moment that will use this API if it's available and fall back using the url hash
Consider this JavaScript library: https://github.com/browserstate/history.js
Use jquery. It can do ajax requests. You cant use window.location because that is made to change the url.

Enabling back/fwd key events for an Ajax Application

I have an application which works heavily on AJAX. However I want to have navigation functionalities in it. To spoof the url, I am changing the location.hash, to generate URL. But if I use back/fwd, only the url changes, but page wont reload. How can I override the hstory.back to reload the page.
I don't know of any other way than continuous polling to implement this behaviour. An implementation might look like this:
var lastHash = '';
function pollHash() {
if(lastHash !== location.hash) {
lastHash = location.hash;
// hash has changed, so do stuff:
alert(lastHash);
}
}
setInterval(pollHash, 100);
You can't exactly capture the back event, but most of these problems have been solved - and a good thing too, it's a hard problem.
Take a look at really simple history (aka RSH) and either implement it or work through it to see how it works.
The answer for this question will be more or less the same as my answers for these questions:
How to show Ajax requests in URL?
How does Gmail handle back/forward in rich JavaScript?
In summary, two projects that you'll probably want to look at which explain the whole hashchange process and using it with ajax are:
jQuery History (using hashes to manage your pages state and bind to changes to update your page).
jQuery Ajaxy (ajax extension for jQuery History, to allow for complete ajax websites while being completely unobtrusive and gracefully degradable).
The balupton answers are really great.
But you also have another jQuery Plugin to handle your ajax requests, it is address.

Categories

Resources