RachelAnn
RachelAnn

Reputation: 33

Backbone.js Uncaught TypeError this.model.each is not a function

Ok, so I'm currently going through a course over Backbone.js where I have to create a View with a list of objects, and a delete button, but I keep getting the error (Uncaught TypeError: this.model.each is not a function) where I have indicated below (//THIS IS WHERE THE ERROR IS BEING THROWN). Any help with this is appreciated!

    //BACKBONE MODEL//
var Vehicle = Backbone.Model.extend( {
    idAttribute: "registrationNumber",

    urlRoot: "/api/vehicles",

    start: function() {
        console.log("Vehicle started.");
    }

});

//BACKBONE MODEL//
var Car = Vehicle.extend( {
    start: function() {
        console.log("Car with registration number XLI887 started.");
    },

    validate: function(attrs) {
        if (!attrs.registrationNumber)
            return "Registration number is required.";
    }
});

var car = new Car({ registrationNumber: "XLI887", color: "Blue" });
car.start();

//BACKBONE COLLECTION//
var Vehicles = Backbone.Collection.extend({
    model: Vehicle,
});

var vehicles = new Vehicles([
    new Vehicle({ car: "Car 1", registrationNumber: "XLI887", color: "Blue"}),
    new Vehicle({ car: "Car 2", registrationNumber: "ZNP123", color: "Blue"}),
    new Vehicle({ car: "Car 3", registrationNumber: "XUV456", color: "Gray"})
]);

var blueCars = vehicles.where({ color: "Blue" });

console.log("Blue Cars", blueCars);

var carRegNumb = vehicles.findWhere({ registrationNumber: "XLI887" });

console.log("Car Reg Numb", carRegNumb);

vehicles.remove(carRegNumb);

vehicles.each(function(vehicle){
    console.log(vehicle);
});

//BACKBONE VIEW//
var VehicleView = Backbone.View.extend({
        tagName: "li",
        className: "vehicle",
        id: "registrationNumber",
        attributes: {
        "data-color": "Blue"
},

        render: function(){
        this.$el.html(this.model.get("car"));

        return this;
    },

    events: {
        "click": "onClick",
        "click .delete": "onClickDelete",
    },

    onClick: function(){
        console.log("Delete Clicked");
    },

    onClickDelete: function(e){
        console.log("Delete Clicked");
    },

    render: function(){
        this.$el.html(this.model.get("car") + " <button>Delete</button>");

        return this;
    }

});

//BACKBONE VIEW//
var VehiclesView = Backbone.View.extend({
    tagName: "ul",
    className: "vehicle",

    id: "registrationNumber",
    attributes: {
        "data-color": "Blue"
    },

    render: function(){
        var self = this;


        this.model.each(function(vehicle){     //THIS IS WHERE THE ERROR IS BEING THROWN
            var vehiclesview = new VehiclesView({ model: car });
            self.$el.append(vehiclesview.render().$el);
        });

        return this;
    }
});

var vehicles = new Vehicles([
    new Vehicle({ car: "Car 1", registrationNumber: "XLI887" }),
    new Vehicle({ car: "Car 2", registrationNumber: "ZNP123" }),
    new Vehicle({ car: "Car 3", registrationNumber: "XUV456" })
    ]);

var vehicleView = new VehicleView({ el: "#vehicles", model: car });
vehicleView.render();

var vehiclesView = new VehiclesView({ el: "#vehicles", model: car});
vehiclesView.render();

Upvotes: 0

Views: 2311

Answers (1)

danillouz
danillouz

Reputation: 6371

It seems to me that you get the error because you're passing in a model instance instead of a collection instance to your vehiclesView. Because the car model instance is not an array, you can't iterate over it using each().

Also I believe you're mixing up your model- and collection views. Your vehiclesView is essentially a collection view and should receive a collection of models. It's job is then to instantiate, render and append a vehicleView (model view) for each Vehicle model in your Vehicles collection.

// Vehicles Collection View.
var VehiclesView = Backbone.View.extend({
    tagName: 'ul',

    className: 'vehicle',

    id: 'registrationNumber',

    attributes: {
        data-color: 'Blue'
    },

    render: function () {

        // This is a collection view, therefore access your data by
        // referencing `this.collection` and NOT `this.model`.
        this.collection.each(function (vehicleModel) {

            // Instantiate a model view for each model in your collection.
            var vehicleView = new VehicleView({
                model: vehicleModel
            });

            // Render and append the `vehicleView`
            this.$el.append(vehicleView.render().$el);
        }, this);

        return this;
    }
});

Then make sure to instantiate a collection using your models and instantiate your collection view by passing said collection into the collection view.

// Instantiate a collection.
var vehicles = new Vehicles([
    new Vehicle({ car: 'Car 1', registrationNumber: 'XLI887' }),
    new Vehicle({ car: 'Car 2', registrationNumber: 'ZNP123' }),
    new Vehicle({ car: 'Car 3', registrationNumber: 'XUV456' })
]);

// Pass the collection to the vehicles collection view.
var vehiclesView = new VehiclesView({
  collection: vehicles  // Passing in a collection and NOT a model.
});

// Render the vehicles collection view.
vehiclesView.render();

Upvotes: 1

Related Questions