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.
Related
The biggest problem is that I even don't really know how to describe the problem I'm asking about. It's the first time in more then a decade of wed development.
I'm working on a Rails 4.1.1 app and using angularjs pretty extensively, though I don't know it well yet. And everything seemed to be working fine up to the moment when I tried to add some browser history manipulation to my app (e.g. changing the displayed url when listing though a paginated list so that that url can be copied and distributed). To do this I added a config to my app.
#app.config ($locationProvider) ->
$locationProvider.html5Mode(true)
And then in my angular controller added the $location binding like this
$scope.$watch 'pagination.cur', (newVal) ->
$scope.loadNews newVal
$location.path("/news").search({page:newVal})
(this is ment to change the url in the browser searchbox when the user goes from one page to another).
That workes well, the url does change appropriately, but all the sudden all the html links on the page got broken. I mean litteraly. I click any link on the page (even outside the controller div), the url in the serchbox changes appropriately, but the turbolinks toes not fire the Ajax request to get the new page content. If I then refresh the page, it loads the correct page.
I know it's really weird. What's weirder, that I don't get any JavaScript errors or anything unusual.
The only way I found to get the links working again - is to remove that initial config.
But when I do it, the $location falls back to hashtag syntax, wich is really not at all what I want.
My only assumption is that there could be some kind of a conflict between angular $location service and turbolinks when handling browser history, but even if that's right, I have no idea how to get around it. And I really need that kind of manipulation, 'cause I'm going to be using it alot in this and other apps.
I really don't know, what other information on this problem may be usefull, don't hasitate to ask for updates. I'll post whatever I can.
P.S. Btw, can this kind of manipulation be done by means of turbolinks? 'Cause it's exactly the same thing turbolinks does when changing the displayed url after page body reload, but I can't find any documentation on its public API for that.
UPDATE
Have no idea what's the source of the problem yet, but it seems to be not related to the turbolinks gem. Removing turbolinks requirements from the application.js file does not change anything.
Using $window.history.pushState instead of $location.path solves the functionality problem, but does not explain the initial bug.
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/
Not sure what i am missing, but I have pushState working on my Backbone based app, where I could click around and have my URL look like www.example.com/route_specified, however if i try to go directly to that page it shows up as not found. If I do www.example.com/#route_specified it works, and quickly changes back to www.example.com/route_specified on the address bar
I am guessing i need to do something in Apache to handle this and make sure that all calls resolve to the index or something like that, but can't find explanation.
Correct. Think about it this way without pushstate enabled. Your server is still trying to serve the page at that route. Since it cannot find the specified document at that location, it throws a 404.
Technically speaking, your server should still produce some sort of result at the url location, then have Backbone take over. In it's simplest form, this is called progressive enhancement. The server should still serve some sort of static page with critical info, which will eliminate issues you will have with SEO. Work your site/app with javascript disabled, serving only the relevant data. Then have Backbone takeover. I have just come across Mashable's redesign, and they integrate progressive enhancement extremely well with Backbone.
If SEO is not a concern, you could always redirect the user to the index page. Just remember that search engines will only index your app page then. If your content is being served dynamically, there wont be any data to index.
Hope this helps.
Thanks
Tyrone
I've been trying to get various routes bookmarkable within my app, and this is possible if I don't have pushState enabled. A user can enter mysite.com/#/view/30 and the proper view renders.
However, if I were to enable pushState and go to mysite.com/view/30 I receive a parse error (navigating there via the root page works fine).
I'm currently utilizing the Backbone.js Boilerplate using Require.js, and the parse error is appearing in my config.js file. I'm fairly certain the issue isn't with Require but I'm not completely sure. Frankly, I don't necessarily know what code to paste here either because I believe I'm more lacking a fundamental understanding a difference between hashbangs vs. pushState.
I've read up on the HTML5 feature, however the answer to my specific question still eludes me.
The page with your Backbone router on does not exist at the path you are pointing to in your pushState. The pushState is purely to change the URL representation. You'd have to do some server config changes to route all of your requests back to a main index file.
I'm studying in backbone.js and I like the routing system. But all users of my site can see there requests, like: http://example.com/#/projects and so on.
How can I hide the routing from a browser's url bar but use that cool backbone feature?
I'm not 100% sure what you want, but if you are asking to remove everything after your domain
and keep http://mysite.com in the address bar, without the hashes (#projects/10) i think you will be dissapointed.
as far as i know, you cannot remove that, since the history and the routing depend on those hashes, thanks to that part of the url, it knows which route you are trying to fetch.
however, it is possible to remove the /#/ part... and make it http://mysite.com/projects
for that you need to use pushstate in the router like this:
Backbone.history.start({pushState: true});
You can put your whole website in an iframe 100% width/height of the page and have your address bar always show root URL...
It will work though it will kill the whole idea behind routes which are supposed to give users fast access to all the states of the app directly with the URL and make any route in your app be bookmarkable and shareable.
Though in the end it's your call :) if you think it's the bet for your app - you know best!