Backbone.js Router history back to initial page - backbone.js

Okay I have googled and googled and can't find anything related to my actual problem.
Basically I have a simple router defined with a few routes all of which can be rendered directly by the server if called directly.
So the backbone history is called like this.
Backbone.history.start({
'pushState': true,
'silent': true
});
I then have simple a very simple navigate
this.navigate($(event.currentTarget).attr('href'), {
'trigger': true
});
This all works correctly except for one flaw.
Lets say you start on the home page of the site which I do not have a backbone route defined for and then click a few links on the site that use the backbone router, you will get routed to the correct page and everything is fine, but then when you click the browser's back button to get back to the home page you end up seeing the contents of the first backbone route and not the actual homepage's contents.
So I am realizing that I need to store the initial page contents so that I can reinsert them into the page once I detect that I am back to the initial page that does not match a route in my Router, and then from there I need to reload in the stored version of my page.
So I would like to know if this sounds right, or if I am going down the wrong path, also does backbone offer anything to help with this scenario that I am just missing? And I can't be the only one who has tried to do this so how have others gotten around this issue?
(Initially I thought there was actually a problem with my code, and not actually this fundamental issue, so I still want to ask this question to figure out how others have accomplished this)

You need to define a route for the homepage. What happens is that each time you follow a link, the current URL is pushed on pushState's stack, and each time you hit the back button the previous URL gets popped and Backbone tries to follow its route. However, when you pop the homepage URL, there's no route that it matches so Backbone doesn't actually do anything, leaving the content as whatever it was the last time a route really did match.

Related

Browser history doubled in angularjs app

So I am using a web app which has an iframe pointing to my angularjs application. If I navigate around the parent web app, I notice that the browser history is doubled up. For example, if I navigate to contacts > about us > home, then the history will be:
- home
- about us
- about us
- contacts
- contacts
If I point the iframe to a simple web page with no angular, then the parent app history works fine. I came across this bug on the angularjs website with a similar issue which appears to have been resolved in an earlier version of angular: https://github.com/angular/angular.js/issues/1054 but it doesn't seem to be resolved for some people. I'm using v1.2.26. Has anyone else experienced this issue?
So it turns out my assumptions about routing as the potential cause were correct, and I can't believe I didn't realize this sooner. Essentially my iframe app routes to different locations through some sort of event. Each route, while it does not impact the parent url, will add a new entry to the browser history (which is normal browser behaviour). The iframe app is designed upon page load to run through a couple routes, thus adding to the browser history, and making it appear like each parent page navigation was doubled.
The question now becomes, is there a way to prevent each route execution from adding the browser history?
UPDATE:
$location.replace() seems to be the only solution I can find. The app makes use of $location.path() a lot to trigger a new route; so I've modified it to be $location.path().replace(); This will replace the current history entry instead of adding a new one.

how to reflect change in URL without adding reloadOnSearch:false to all routes

I recently added i18n to my site, and I want the selected language to reflect on the URL.
So I added $location.search('lang', language); in my code.
however - now every page I enter refresh. so I started adding reloadOnSearch:false to all routes, but then I got the feeling I am doing something wrong.
What is the proper way to implement this?

Backbone router: Use hashbangs

I was setting up a simple router in Backbone.js while I noted an issue, I googled for a long time and found some solutions.
The problem is that whenever I navigate to a url, this url will work while I'm inside the app itself, but once you bookmark it and return it will obviously return a 404 since that page doesn't exist.
Backbone.history.navigate('test', true);
This will navigate to http://www.domain.com/test, which is great, but once you refresh the same URL it returns a 404.
There are ways to get this to work with using a specific .htaccess file, but I'm building this inside an existing website, so I can't use this.
Is there a way in Backbone.js to revert to just using hashbangs? My url would then look like this `http://www.domain.com/#!/test
This might not be the cleanest URL, but at least it will work.
Or am I just missing something obvious here? It can't be that I'm the only person with this problem.
You're using pushState according to your url, so you've got 2 main options:
stop using pushState when starting Backbone history (which would be the equivalent of using a hashbang, except for SEO)
have your server return a page for every URL your app generates (it can be the same exact page)
In the second case, if you don't care about SEO, you can have a catch all rule always returning (e.g.) index.html containing your Backbone app. When you start Backbone's history, it will lokk at the URL and navigate to the proper page (although you might have a "double render" effect).
If you're worried about SEO, you need to return page content for SEO along with your Backbone app.

Alternative to the Backbone router without hash fallbacks and better back/forward state support?

I am currently using the Backbone router for my SPA. It sort of works OK, but I am having a number of small issues:
The problem is - I want to either have pushState navigation or none, meaning - app state gets executed (when I pass the "initial" URL to the router or I trigger a route via JS), but the address bar doesn't change. I don't want the hashChange fallbacks for IE9. It will work just fine if IE9 does not get the back button and the changing address bar, but still retains navigation state within the application. I can then show the users a URL which they can bookmark and the server will route that page and the app state will bootstrap based on the initial URL. The address bar not changing in IE during in-app navigation is a compromise I am willing to accept.
Another problem that I have is that I am using navigate(url, {trigger: true}) for my intercepted HREFs, and the back button doesn't work (does nothing). But I really need to change app state on forward/back navigation, even if it gets rebuilt for that particular URL - I'd rather rebuild the state.
What are my options in terms of routers that I could use? Like I said, I don't want to have hashbang fallbacks (meaning - I only want to have ONE way of representing URLs in the application, period).
What should I use? Director.js? History.js? There seems to be quite a number of router/history libraries out there but which one is the closest to what I'm looking for?..
Supposing you have Modernizr around scanning the HTML5 history support, if I understand well wouldn't a fast solution be, in your main layout js file, to add as event
'click a' : "navigate"
and add the function navigate to this layout as follow
navigate : function(e){
if(!Modernizr.history) document.location.href = $(e.currentTarget).attr("href");
},
to optimize, you could of course bind that only if history is not supported,don't forget to include "modernizr" in your layout. Hope this is an interesting answer for you..

Backbone router, pushstate, and relative urls

I'm making my first backbone app. I have pushstate enabled. In the router I have two routes.
'link1(/)' : 'link1Route',
'link2(/)' : 'link2Route'
On my link1 page, I have a link pointing to link 2 like so:
Link2
I click on the link, the router takes over and I go to link2Route as expected. However, if I hover over the link, the status bar indicates that the link is at domain.com/link1/link2 rather than domain.com/link2. This is correct given the relative url structure on the link1 page. Unfortunately, if a user decides to open the link in a new window or tab, backbone's router will not take effect. This is expected since opening in a new window or tab results in a new page load from the server. The problem of course, is that domain.com/link1/link2 does not exist.
What are some ways of dealing with this situation? Thanks.
As mateusmaso indicated, you need to change your link target to "/link2" (i.e. including the "/").
In addition, when implementing pushState, don't forget you need your server to respond with content if a user requests the "domain.com/link2" URL. The response can be index.html if you wish, but the server must return a page for that URL.
If you return index.html for all your Backbone-related URLs, when your Backbone app gets started the route-handling code will get fired and the proper data will be displayed.
If you want to learn more about routing and how to manage it properly without needing to pass trigger: true when calling navigate, check out pages 32-46 of this free sample pdf: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf (full disclosure, I'm the book author)
You must serve the correct index.html at the server level — since this is before the JavaScript even loads on the page.
http://readystate4.com/2012/05/17/nginx-and-apache-rewrite-to-support-html5-pushstate/

Resources