最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Backbone Routes with pushState on are not working when you refresh page - Stack Overflow

programmeradmin1浏览0评论

I have a simple router:

Erin.Router = Backbone.Router.extend({
    initialize: function() {
        Backbone.history.start({pushState: true});
    },
    routes: {
        '' : 'index',
        'project/:img' :'project',
    },
    index: function() {
        var galleryView = new Erin.GalleryView();
    },
    project: function(img) {
        console.log(img);
    }
}); 

The template for the Erin.GalleryView is(thinking there might be an issue there):

<script type="text/template" id="gallery-grid">
        <a href="/project/<%= id %>">
            <img src="<%= thumbnail %>" />
            <span class="desc">
                <div class="desc-wrap">
                    <p class="title"><%= title %></p>
                    <p class="client"><%= client %></p>
                </div>
            </span>
        </a>
    </script>

The GalleryView and the GalleryItem code.

Erin.GalleryItem = Backbone.View.extend({
    tagName: 'div',
    className: 'project-container',
    //Grab the template html
    template: _.template($('#gallery-grid').html()),
    //Set up the render function
    render: function() {
        //What is the $el in this case?
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

Erin.GalleryView = Backbone.View.extend({
    el: '#projects',
    initialize: function() {
        //create new collection
        this.col = new Erin.Gallery();
        //Listen to all events on collection
        //Call Render on it
        this.listenTo(this.col,'all',this.render);
        //Fetch data
        this.col.fetch();
    },
    render: function() {
        //Get reference to the view object
        var that = this;
        //Empty div
        this.$el.empty();
        //For each model in the collection
        _.each(this.col.models, function(model){
            //call the renderItem method
            that.renderItem(model);
        },this);
    },
    renderItem: function(model) {
        //create a new single item view
        var itemView = new Erin.GalleryItem({
            model:model
        });
        //Append items to to element, in this case "#projects"
        this.$el.append(itemView.render().el);  
    }
});

Then I have a document ready

$(function() {
    var router = new Erin.Router();
    $('#projects').on('click', 'a[href ^="/"]', function(e){
        e.preventDefault();
        router.navigate($(this).attr('href'),{trigger: true});
    });
});

When you load the page and click one of the links in the #project section, everything behaves as it should, if you refresh that page however, I get an error that breaks the page.

From the console:

Uncaught SyntaxError: Unexpected token < js/jquery.js:1
Uncaught SyntaxError: Unexpected token < js/underscore-min.js:1
Uncaught SyntaxError: Unexpected token < js/backbone.js:1
Uncaught SyntaxError: Unexpected token < erin.js:1

It also states stuff like:

Resource interpreted as Script but transferred with MIME type text/html: "http://localhost:8888/project/js/backbone.js". 

For all the links and scripts in the head of the document.

Which all seem to point at the first line of the index.html file. So if I click a link, it will console the img id I am looking for from my data, if I refresh the page OR type that link in, I get the errors above. Am I correct in thinking I should be able to save the links domain/project/coolthing and have that work when someone es to the page. Have I missed something? Implemented something weird? A nudge in the right direction would be much appreciated.

Thanks.

I have a simple router:

Erin.Router = Backbone.Router.extend({
    initialize: function() {
        Backbone.history.start({pushState: true});
    },
    routes: {
        '' : 'index',
        'project/:img' :'project',
    },
    index: function() {
        var galleryView = new Erin.GalleryView();
    },
    project: function(img) {
        console.log(img);
    }
}); 

The template for the Erin.GalleryView is(thinking there might be an issue there):

<script type="text/template" id="gallery-grid">
        <a href="/project/<%= id %>">
            <img src="<%= thumbnail %>" />
            <span class="desc">
                <div class="desc-wrap">
                    <p class="title"><%= title %></p>
                    <p class="client"><%= client %></p>
                </div>
            </span>
        </a>
    </script>

The GalleryView and the GalleryItem code.

Erin.GalleryItem = Backbone.View.extend({
    tagName: 'div',
    className: 'project-container',
    //Grab the template html
    template: _.template($('#gallery-grid').html()),
    //Set up the render function
    render: function() {
        //What is the $el in this case?
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

Erin.GalleryView = Backbone.View.extend({
    el: '#projects',
    initialize: function() {
        //create new collection
        this.col = new Erin.Gallery();
        //Listen to all events on collection
        //Call Render on it
        this.listenTo(this.col,'all',this.render);
        //Fetch data
        this.col.fetch();
    },
    render: function() {
        //Get reference to the view object
        var that = this;
        //Empty div
        this.$el.empty();
        //For each model in the collection
        _.each(this.col.models, function(model){
            //call the renderItem method
            that.renderItem(model);
        },this);
    },
    renderItem: function(model) {
        //create a new single item view
        var itemView = new Erin.GalleryItem({
            model:model
        });
        //Append items to to element, in this case "#projects"
        this.$el.append(itemView.render().el);  
    }
});

Then I have a document ready

$(function() {
    var router = new Erin.Router();
    $('#projects').on('click', 'a[href ^="/"]', function(e){
        e.preventDefault();
        router.navigate($(this).attr('href'),{trigger: true});
    });
});

When you load the page and click one of the links in the #project section, everything behaves as it should, if you refresh that page however, I get an error that breaks the page.

From the console:

Uncaught SyntaxError: Unexpected token < js/jquery.js:1
Uncaught SyntaxError: Unexpected token < js/underscore-min.js:1
Uncaught SyntaxError: Unexpected token < js/backbone.js:1
Uncaught SyntaxError: Unexpected token < erin.js:1

It also states stuff like:

Resource interpreted as Script but transferred with MIME type text/html: "http://localhost:8888/project/js/backbone.js". 

For all the links and scripts in the head of the document.

Which all seem to point at the first line of the index.html file. So if I click a link, it will console the img id I am looking for from my data, if I refresh the page OR type that link in, I get the errors above. Am I correct in thinking I should be able to save the links domain./project/coolthing and have that work when someone es to the page. Have I missed something? Implemented something weird? A nudge in the right direction would be much appreciated.

Thanks.

Share Improve this question edited Oct 10, 2013 at 7:20 Mohit 2,24919 silver badges31 bronze badges asked Oct 1, 2013 at 19:37 RchristianiRchristiani 4443 silver badges18 bronze badges 3
  • could you add the code for GalleryView? At least the portion which loads the template? – providencemac Commented Oct 6, 2013 at 16:06
  • @providencemac Added that in the top there. Hopefully that helps – Rchristiani Commented Oct 6, 2013 at 17:22
  • Where to exactly add that router parsing thing, I have no idea! – Nobody Commented Dec 7, 2017 at 12:10
Add a ment  | 

3 Answers 3

Reset to default 8 +50

You have a problem server-side. You're probably already half-way to the solution.

It looks like you have correctly configured your server to send your app HTML on any hit, except for your assets (js, css) which have precedence.

The problem lies in you main HTML, where your JS files are referenced with a relative path. When you reload after pushState has updated the URL to /project/1 the base URL bees /project/.

ie. you have

<script src="js/backbone.js"></script>

when you should have

<script src="/js/backbone.js"></script>

As a result, when the browser tries to load backbone.js it doesn't find it (/project/js/backbone.js doesn't exist), and hits the server catchall that delivers the app HTML (hence the parsing error that chokes on <).

My explaination may not be crystal clear, it's pretty late over here, but I'm sure you'll understand !

The problem is in the href you are using in the template. The Backbone Router is watching for changes to the hash portion of the site URL, which is the content after the # symbol.

So your href should be: <a href="/#project/<%= id %>"> (notice the # before "project")

In that fashion, you won't even need a click handler at all, the Router will automatically capture the hash change event and route accordingly.

Both thibauts' and providencemac's assessments are right. Either don't use pushState and go with hash links or put a rewrite rule in your server to send the statics.

initially when you load you load this url -

http://localhost:8888

like wise url of your statics is along this

http://localhost:8888/js/backbone.js

the actually problem is when you use pushState and visit a link. Your browser url bees. something like this -

http://localhost:8888/project/some_img_id

Now when you try to reload the page, the index file is taken from this url -

http://localhost:8888/project/your_default.file   [index.html]

Which your server fails to find and defaults to index file at

http://localhost:8888/your_default.file

And when the browser tries to access the statics it again defaults to index file

http://localhost:8888/project/js/backbone.js

thats why the error. as it finds '<' character which is invalid toekn in javascript.

Uncaught SyntaxError: Unexpected token < js/jquery.js:1

this error cause the file its trying to parse is backbone.js a javascript but its gets your index.html

Resource interpreted as Script but transferred with MIME type text/html: "http://localhost:8888/project/js/backbone.js".
发布评论

评论列表(0)

  1. 暂无评论