Search code examples
javascriptjquerybackbone.jsmarionettebackbone-views

Model not firing parse function


I'm having a problem where my backbone model isn't parsing something correctly. Here is the listing.js:

SpendYourSavings.Models.Listing = Backbone.Model.extend({
    urlRoot: "api/listings/",
    images: function() {
        this._images = this._images || new SpendYourSavings.Collections.Images([], { listing: this });
        return this._images;
    },
    reviews: function() {
        this._reviews = this._reviews || new SpendYourSavings.Collections.Reviews([], { listing: this });
        return this._reviews;
    },
    shop: function() {
        this._shop = this._shop || new SpendYourSavings.Models.Shop([], { listing: this });
        return this._shop;
    },


    parse: function(data) {
        if(data.images) {
            this.images().set(data.images, { parse: true });
            delete data.images;
        }
        if(data.reviews) {
            this.reviews().set(data.reviews, { parse: true });
            delete data.reviews;
        }
        if(data.shop) {
            this.shop().set(data.shop, { parse: true });
            delete data.shop;
        }
        return data;
    }
});

Images and reviews work, but shop doesn't quite work. It sets the attributes of shop correctly, but it doesn't set the image properly.

Here is the shop.js:

SpendYourSavings.Models.Shop = Backbone.Model.extend({
    urlRoot: "/api/shops",

    reviews: function() {
        this._reviews = this._reviews || new SpendYourSavings.Collections.Reviews([], {});
        return this._reviews;
    },

    listings: function() {
        this._listings = this._listings || new SpendYourSavings.Collections.Listings([], {});
        return this._listings;
    },

    user: function() {
        this._user = this._user || new SpendYourSavings.Models.User([], {});
        return this._user;
    },

    image: function() {
        this._image = this._image || new SpendYourSavings.Models.Image([], {});
        return this._image
    },

    parse: function(data) {
        console.log("shop parse data: " + data);
        debugger
        if(data.listings) {
            this.listings().set(data.listings, { parse: true });
            delete data.listings;
        }
        if(data.reviews) {
            this.reviews().set(data.reviews, { parse: true });
            delete data.reviews;
        }
        if(data.user) {
            this.user().set(data.user, { parse: true });
            delete data.user;
        }
        if(data.image) {
            debugger
            this.image().set(data.image, { parse: true });
            delete data.image;
        }
        return data
    }

});

The parse function in the shop.js never even when I receive a shop in the listing.js parse function! shop.image() doesn't get set to an image model properly, so I have to call something wonky like shop.get('image').url to get the url.


Solution

  • Presumably, the reason you're memoizing the image model in the shop is to maintain listeners and keep a single instance of that model around.

    Collection#set takes a parse option that tells it to call parse on all the models that were set on the collection. Model#set is the method called immediately after calling parse using the attributes returned from parse.

    In this case, we want to call #set on the associated shop model using the parsed attributes. So first lets call parse. It should look something like this:

    SpendYourSavings.Models.Listing = Backbone.Model.extend({
        urlRoot: "api/listings",
    
        images: function() {
            this._images = this._images || new SpendYourSavings.Collections.Images([], { listing: this });
            return this._images;
        },
    
        reviews: function() {
            this._reviews = this._reviews || new SpendYourSavings.Collections.Reviews([], { listing: this });
            return this._reviews;
        },
    
        shop: function() {
            // Notice the first argument is an object when initializing models.
            this._shop = this._shop || new SpendYourSavings.Models.Shop({}, { listing: this });
            return this._shop;
        },
    
        parse: function(data) {
            if(data.images) {
                this.images().set(data.images, { parse: true });
                delete data.images;
            }
            if(data.reviews) {
                this.reviews().set(data.reviews, { parse: true });
                delete data.reviews;
            }
            if(data.shop) {
                var shopParams = this.shop().parse(data.shop);
                this.shop().set(shopParams);
                delete data.shop;
            }
            return data;
            }
        }
    });