3

I'm improving my knowledge about Backbone.js and have this code sample taken from a tutorial. (http://bardevblog.wordpress.com/2012/01/16/understanding-backbone-js-simple-example/)

This example will not access the server for now, so to simulate the retrieval of data from the server I have a file name movies.json.

What I am trying to do:

  • Add json data in local storage (using localStorage adapter)
  • For this I am using Backbone.ajaxSync, Which Is Given to the alias Backbone.sync by the localStorage adapter: I created the method refreshFromServer () to do this
  • The reason for doing this is that I'm trying to implement a way to get data only one time (and only refresh when i need to)

My issues:   I'm having an error "Uncaught Error: 'url' property or function must be specified" when I call refreshFromServer (). I do not understand why because I set the url collection. (url : "scripts/data/movies.json" )

Sample code

var Theater = {
    Models : {},
    Collections : {},
    Views : {},
    Templates : {}
}

Theater.Models.Movie = Backbone.Model.extend({})
Theater.Collections.Movies = Backbone.Collection.extend({
    model : Theater.Models.Movie,
    localStorage : new Backbone.LocalStorage("MovieStore"), // Unique name within your app.
    url : "scripts/data/movies.json",
    refreshFromServer : function() {
        return Backbone.ajaxSync.apply(this, arguments);
    },
    initialize : function() {
        console.log("Movies initialize")
    }
});

Theater.Templates.movies = _.template($("#tmplt-Movies").html())

Theater.Views.Movies = Backbone.View.extend({
    el : $("#mainContainer"),
    template : Theater.Templates.movies,

    initialize : function() {

        this.collection.bind("reset", this.render, this);
    },

    render : function() {
        console.log("render")
        console.log(this.collection.length);

    }
})

Theater.Router = Backbone.Router.extend({
    routes : {
        "" : "defaultRoute"
    },

    defaultRoute : function() {
        console.log("defaultRoute");
        Theater.movies = new Theater.Collections.Movies()
        new Theater.Views.Movies({
            collection : Theater.movies
        });
        Theater.movies.refreshFromServer();
        //Theater.movies.fetch();
        console.log(Theater.movies.length)
    }
})

var appRouter = new Theater.Router();
Backbone.history.start();

Notes:

  • If a comment localStorage property in the collection

    Theater.Models.Movie = Backbone.Model.extend({}) Theater.Collections.Movies = Backbone.Collection.extend({ model : Theater.Models.Movie, //localStorage : new Backbone.LocalStorage("MovieStore") ... });

    and then in router call normal fetch method

    Theater.Router = Backbone.Router.extend({ routes : { "" : "defaultRoute" },

    defaultRoute : function() {
    
        Theater.movies = new Theater.Collections.Movies()
        new Theater.Views.Movies({
            collection : Theater.movies
        });
        //Theater.movies.refreshFromServer();
        Theater.movies.fetch();
    }
    

    })

I can see the json list correctly in my view

  • If I use the localStorage property in the collection and then call the standard fetch () method, I see only an empty list (I think it is normal as it is read from the local storage and is empty)

  • The error only occurs when using the method refreshFromServer () witch use Backbone.ajaxSync (alias for backbone.sync)

Sandcar
  • 892
  • 1
  • 9
  • 21

1 Answers1

4

Err... my bad. The refreshFromServer implementation is from my answer to your earlier question., and it's completely, uselessly wrong.

Backbone.sync expects arguments (method, model, options), but as it stands, it doesn't get what it needs from refreshFromServer because the refresh method simply sends forward whatever arguments it gets. Sorry for the mistake.

The correct, working implementation would be:

refreshFromServer : function(options) {
    return Backbone.ajaxSync('read', this, options);
}

It can be used either via success / error callbacks passed to the options hash:

this.collection.refreshFromServer({ success: function() { /* refreshed... */ });

Or via the jqXHR Promise API:

this.collection.refreshFromServer().done(function() { /* refreshed... */ })

Or not signing up for callbacks and waiting for the collection reset event like in your example:

this.collection.bind("reset", this.render, this);
this.collection.refreshFromServer();

This should work. Please let me know if it doesn't. I fixed my answer in the previous question too, in case someone stumbles onto it.

Edit: To save the data to local storage after refreshing you need to manually save each of the models:

var collection = this.collection;
collection.refreshFromServer({success: function(freshData) {
    collection.reset(freshData);
    collection.each(function(model) {
        model.save();
    });
}});
Community
  • 1
  • 1
jevakallio
  • 35,324
  • 3
  • 105
  • 112
  • thank you so much @ fencliff I tried the way you say and now I no longer have the error "The" url "property ..." (Which is good :)). But now when I call refreshFromServer () I have an empty list. When using Chrome console i notice: - Json file that is properly called - Local storage is created but without any key / value a question: when the json is returned is this automatically placed in localStorage ? I tried your suggestion in this code example and also in my previous question. – Sandcar Jan 12 '13 at 01:51
  • 1
    @Sandcar - the local storage is not automatically populated. You have to `.save()` each model in the collection. I edited my answer, see above. – jevakallio Jan 12 '13 at 02:03
  • now i get this error "Uncaught TypeError: Object [object Object],[object Object]... has no method 'each' " . It returns my json objects but the collection but I can not iterate over the collection. Once again, thanks for your patience – Sandcar Jan 12 '13 at 02:26
  • 1
    To get a reference to the collection in the callback, use the `success` callback as per my edit. – jevakallio Jan 12 '13 at 10:15
  • still the same problem in my previous post. I think it's because on the return callback the collection is not a collection of models but a raw javascript array, and does not have an each function. So a try anoher way. **See my edit in your previous answer**. can you check if this is the right approach ? Thanks – Sandcar Jan 12 '13 at 11:57
  • 1
    @Sandar, yes, you're right. See my last, and hopefully final edit. It seems I still wasn't paying enough attention. Also please note that if your new data doesn't have some models that are in the local storage, this won't automatically clear them. – jevakallio Jan 12 '13 at 13:25
  • 1
    Awesome! Works like a charm! I'll add a comment in my [previous question](http://stackoverflow.com/questions/14071203/backbone-collection-from-json-file-and-cache-on-localstorage) with a link to here in case someone stumbles onto a similiar problem and need help. thank you very much! – Sandcar Jan 12 '13 at 14:17
  • You guys rock! I've had this same issue in a backbone app that I'm working on, and this was spot on! many thanks – Merlin Feb 25 '15 at 14:26