lch
lch

Reputation: 4931

Backbone Fetch success callback not executing when fetch response is an empty array

I have Person model and I am retrieving a person info inside a view. The success callback FetchSuccess executes when the response has an object. But when response is empty, the callback is not called. Any Guess?

Models.Basic = Backbone.Model.extend({
    parse: function(response) {
        return response;
    }
});

Models.PersonModel = Backbone.Model.extend({
    url: function() {
        return '/person/' + this.data.id;
    }
});

Backbone.View.extend({

    template: Templates['template'],

    initialize: function(options) {
        this.id = options.id;
        _.bindAll(this, 'FetchSuccess');

        this.personModel = new Models.PersonModel();
        this.model = new Models.Basic();
        this.fetchData();
        return this;
    },

    render: function() {
        this.$el.append(this.template(this.model.toJSON()));
    },

    fetchData: function() {
        this.personModel.data = {
            id: this.id
        };
        this.personModel.fetch({
            context: this,
            success: this.FetchSuccess
        });
    },

    FetchSuccess: function() {
        this.model.set({
            name: this.personModel.get('name');
        });
        this.render();
    }
});

Upvotes: 0

Views: 358

Answers (1)

Emile Bergeron
Emile Bergeron

Reputation: 17430

this.personModel = new Models.PersonModel();

This is a Backbone Model, not a collection.

this.personModel.fetch({
    reset: true, // this doesn't exist on model
    success: this.FetchSuccess
});

You can't fetch a model without an id. Also, the model, when fetching, expects an object to be returned.

If you want to fetch a specific person, give an id to the model, then fetch.

this.personModel = new Models.PersonModel({ id: "id_here" });
// ...
this.personModel.fetch({
    context: this,
    success: this.FetchSuccess
});

Here's the code with the corrections

// parse isn't needed if you're not going to parse something
Models.Basic = Backbone.Model.extend({});

Models.PersonModel = Backbone.Model.extend({
    urlRoot: 'person/', // this handles putting the id automatically
});

Backbone.View.extend({
    template: Templates['template'],

    initialize: function(options) {
        this.id = options.id;

        // pass the id here
        this.personModel = new Models.PersonModel({ id: this.id });

        this.model = new Models.Basic();
        this.fetchData();

        // makes no sense in the initialize since it's never called 
        // manually and never used to chain calls.
        // return this; 
    },

    render: function() {
        // render should be idempotent, so emptying before appending
        // is a good pattern.
        this.$el.html(this.template(this.model.toJSON()));

        return this; // this is where chaining could happen
    },

    fetchData: function() {
        // This makes no sense unless you've stripped the part that uses it.
        // this.personModel.data...

        this.personModel.fetch({
            context: this, // pass the context, avoid `_.bindAll`
            success: this.onFetchSuccess,
            error: this.onFetchError
        });
    },

    onFetchSuccess: function() {
        this.model.set({
            name: this.personModel.get('name')
        });
        this.render();
    },
    onFetchError: function() { this.render(); }

});

You could catch the error with the error callback, or just do nothing and render by default, and re-render on fetch.

You could also listen to the model events (inside the initialize):

this.listenTo(this.personModel, {
    'sync': this.FetchSuccess,
    'error': this.onFetchError
});
this.personModel.fetch();

Upvotes: 1

Related Questions