1

ok I have

{{#each mainmenu}}
<li>
    <a href="#pages/{{this.url}}"><h2>{{this.name}}</h2></a>
</li>
{{/each}}

and in my router

routes: {
    '': 'index',
    'pages/firstpage' : 'firstpage',
    'pages/secondpage' : 'secondpage',
    'pages/thirdpage' : 'thirdpage'
},
initialize: function () {
   Backbone.history.start({pushState: false});
}

and my json file is:

{
    "name":"First page",
    "id":"1",
    "url":"firstpage"
},
{
    "name":"Second page",
    "id":"2",
    "url":"secondpage"
},
{
    "name":"Third page",
    "id":"3",
    "url":"thirdpage"
}

the way it is right now my URL is "#pages/secondpage" - how can i get the URL to display "pages/secondpage" - i tried "pushState:true" which didnt work... then in my mainmenu.js view I added an event:

events: {
     'click a.second': 'secondpage'
},

secondpage: function() {
    var secondpageRouter = new Backbone.Router();
    var route = 'pages/secondpage';
    secondpageRouter.navigate(route, {trigger: true});
  }

but that didnt work either... when I remove the "#pages/" from the anchor above, I almost get the URL I want "pages/secondpage" - but it says "URL could not be found" after clicking the link. So what's going on here???

Please help anyone?

SHT
  • 700
  • 4
  • 18
  • 39

1 Answers1

2

Understand that you need to be able to serve these urls from the server if necessary, read the docs here: http://backbonejs.org/#History

Then you need to do at least three things.

First, after you have defined your routers, call Backbone.history and make sure pushState is true:

Backbone.history.start({ pushState: true })

Second, get rid of all the # in your links, like this:

<a href="pages/{{this.url}}"><h2>{{this.name}}</h2></a>

Third, and this is important, you need to intercept all clicks on local links and prevent their default behavior, which would be to route you to a new page. This is easy with jQuery:

$(document).on("click", "a[href^='/']", function(event){
  event.preventDefault();
  RouterNameGoesHere.navigate($(event.target).attr("href"), {trigger: true});
});

If you aren't using jQuery, listen to link click events in your views deal with the url in your event handlers. I modified your code to add the event argument and event.preventDefault():

events: {
  'click a.second': 'secondpage'
},

secondpage: function(event) {
  event.preventDefault();
  var secondpageRouter = new Backbone.Router();
  var route = 'pages/secondpage';
  secondpageRouter.navigate(route, {trigger: true});
}

Here is an interesting blog post about this issue

RustyToms
  • 7,600
  • 1
  • 27
  • 36
  • The most important bit from the docs: *Note that using real URLs requires your web server to be able to correctly render those pages, so back-end changes are required as well. For example, if you have a route of /documents/100, your web server must be able to serve that page, if the browser visits that URL directly. For full search-engine crawlability, it's best to have the server generate the complete HTML for the page ... but if it's a web application, just rendering the same content you would have for the root URL, and filling in the rest with Backbone Views and JavaScript works fine.* – RustyToms Dec 11 '13 at 01:11
  • Great! that worked! What I noticed is, that when I'm using my localhost with the URL "localhost/projectfolder/projectname" and then click the secondpage-anchor it makes my URL "localhost/pages/secondpage" - how to keep the projectfolder and projectname? – SHT Dec 11 '13 at 10:34
  • @SHT, whatever you want in your url should be in your link. You can then spoof the route somehow, but if that is the url you want then you should include it in your routes as well. So `href="projectfolder/pages/{{this.url}}"` and the route would be `/projectfolder/pages/secondpage`, etc. – RustyToms Dec 11 '13 at 10:41
  • And while we are at it, it doesn't make sense to make a new router every time you want to navigate. Make the router one time, and save it as a global variable. Then call the global variable when you need the router. That way the back and forward buttons will work. They probably don't work for you as it is, right? – RustyToms Dec 11 '13 at 10:42
  • Yes, you are absolutely right. Where to declare that global variable? – SHT Dec 11 '13 at 10:48
  • @SHT Here is my code for my Backbone app: `window.AFB = AutoFormBot = { Models: {}, Collections: {}, Views: {}, Routers: {}, initialize: function($rootEl, forms){ console.log("AutoFormBot initialized"); AFB.formCollection = new AFB.Collections.Forms(forms); new AFB.Routers.FormRouter($rootEl); Backbone.history.start(); } };` So it is `AFB.Routers.FormRouter` for me, and I declare it right when I am starting up my app. I only need one router. The `Backbone.history.start()` is what makes the forward and back buttons work. – RustyToms Dec 11 '13 at 10:52
  • Feel free to accept this answer. I am new and I could use the rep, and I think this is something that could help others in the future. – RustyToms Dec 11 '13 at 10:55
  • I've read that it kind of depends on server-setup to respond to deep linking? Then how am I supposed to test it on localhost?? (just an open thought) – SHT Dec 11 '13 at 13:25