Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically changing url in Backbone

I was trying to dynamically change the url inside the router but couldn't manage to do it, it keeps returning to the base Collection URL. Here i posted the code with the 3 different collections which apart from pointing to three different urls they do exactly the same. I have only one model and three collections that depend on that model and they even render the same view. How can i dynamically change the url so i can create only one Collection and one Model? Is it best pracitce for a case like this?

    // MODELS & COLLECTIONS 
    window.Post = Backbone.Model.extend({
            urlRoot:  function() {
                    return 'http://localhost:5000/json/guides/:id'
            }
    })

    App.Collections.RecentPosts = Backbone.Collection.extend({
            model: Post,
            url:'http://localhost:5000/json/posts/recent',
    })
    App.Collections.PopularPosts = Backbone.Collection.extend({
            model: Post,
            url:'http://localhost:5000/json/posts/popular',
    })
    App.Collections.FeaturedPosts = Backbone.Collection.extend({
            model: Post,
            url:'http://localhost:5000/json/posts/featured',
    })

    // CONTROLLER
    App.Controllers.Documents = Backbone.Router.extend({
            routes:{
            "recent"                : "recent",
            "popular"         : "popular",
            "featured"          : "featured",
            },

            recent: function(){
                //.... same as featured ?
            },
            popular: function(){
                //.... same as featured ?
            },
            featured: function(){
                    $("#browser").empty();
                    var collection = new App.Collections.Posts();
                    collection.fetch({
                                success: function(col,posts){
                                    new App.Views.GuideView({collection: posts});
                                },
                                error: function(error){
                                    console.log(error)
                                }
                        })
            }
    });
like image 624
Maroshii Avatar asked Oct 02 '12 18:10

Maroshii


2 Answers

There are numerous different ways of doing this. Here's what's probably going to be 'best practice'.

App.Controllers.Documents = Backbone.Router.extend({
        routes:{
        "recent"                : "recent",
        "popular"         : "popular",
        "featured"          : "featured",
        },

        initialize: function () {
            this.collection = new App.Collections.Posts();
        },

        _showPage: function (config) {
            $("#browser").empty();

            this.collection.fetch({
                url: config.url,
                success: function(col,posts){
                    new App.Views.GuideView({collection: posts});
                },
                error: function(error){
                    console.log(error)
                }
            });
        },

        recent: function(){
            this._showPage({url:'http://localhost:5000/json/posts/recent'});
        },
        popular: function(){
            this._showPage({url:'http://localhost:5000/json/posts/popular'});
        },
        featured: function(){
           this._showPage({url:'http://localhost:5000/json/posts/featured'});
        }
});

Since I really don't know how complicated your page is going to get, this is probably the best I can do without more information. But, the idea is that "this.collection" is set on the routers initialization.. so you can keep reusing it. The _showPage method does whatever basic tasks you need done to show the page, and the methods called by the routes use it to do whatever basic stuff needs done before going into detail. The url passed into the config would simply tell the collection where to get its information from - I'm assuming that all of your data has the same format and 'is the same thing'.. just different filters.

You can probably do a similar thing with App.Views.GuideView:

App.Controllers.Documents = Backbone.Router.extend({
        routes:{
        "recent"                : "recent",
        "popular"         : "popular",
        "featured"          : "featured",
        },

        initialize: function () {
            this.collection = new App.Collections.Posts();
            this.view = new App.Views.GuideView({collection: this.collection});
        },

        _showPage: function (config) {
            $("#browser").empty();

            this.collection.fetch({
                url: config.url,
                success: _.bind(function(col,posts){
                    this.view.render();
                }, this),
                error: function(error){
                    console.log(error)
                }
            });
        },

        recent: function(){
            this._showPage({url:'http://localhost:5000/json/posts/recent'});
        },
        popular: function(){
            this._showPage({url:'http://localhost:5000/json/posts/popular'});
        },
        featured: function(){
           this._showPage({url:'http://localhost:5000/json/posts/featured'});
        }
});

The 'render' would just rebuild the view, and since you've already got the collection referenced in the view as "this.options.collection" (or you could add an 'initialize' to the view and set this.collection to be this.options.collection). When the collection gets updated, all of that information is by reference in the view.. so no need to reset it.

like image 190
Stephen Avatar answered Oct 04 '22 13:10

Stephen


I think the best pratice would be to have 3 collections, each with it's on URL and properties.

This makes the code easier to maintain as you can assign different events and listeners to them in a separate file instead of having a "God Collection" that have all the logic inside it.

Of course you can still be DRY and keep a helper object or a parent collection with code that is commmon to all those collections.

like image 39
Cristiano Fontes Avatar answered Oct 04 '22 13:10

Cristiano Fontes