简体   繁体   中英

Backbone.js - Not able to trigger an event in a collection

I'm fairly new to JavaScript and Backbone and I came across this error.

Router = Backbone.Router.extend({

    routes: {
        ":albumID": "load"

    },

    load: function (albumID) {
        if (controller.collectionInitialized == true) {
            console.log("RESET");
            album.trigger("clear");
        }

        var album = new Album([], {
            title: albumID
        });

        controller.trigger("collectionInit");
        controller.trigger("switchAlbum", albumID);
    }
});

Controller = Backbone.Model.extend({

    currentAlbum: "",
    collectionInitialized: false,

    initialize: function () {
        console.log("controller is initialized");
        this.on("switchAlbum", function (newAlbum) {
            this.currentAlbum = newAlbum;

        });

        this.on("collectionInit", function () {
            this.collectionInitialized = true;
        });
    }
});

Album = Backbone.Collection.extend({

    initialize: function (models, options) {
        this.on("clear", this.clear);
    },
    clear: function () {
        this.reset();
        this.off();
    }

});

I get this error: Unable to get property 'trigger' of undefined or null reference . The if statement makes sure that album already exists before triggering clear . Previously I tried just calling album.reset() directly but got the same error. My guess is that it's some kind of scoping problem, could someone please point me in the right direction?

It's true that in Javascript variables are function-scoped , meaning they're visible all over their local scope (ie the function host), but instantiation is a different beast.

load: function (albumID) {

    if (controller.collectionInitialized == true) {
        console.log("RESET");
        album.trigger("clear");
    }

    var album = new Album([], {
        title: albumID
    });

    controller.trigger("collectionInit");
    controller.trigger("switchAlbum", albumID);
}   

You create a new Album after you call method trigger on album, thus resulting in a null reference.

Also, even if you call the function twice (ie the first time having controller.collectionInitialized as false , and the second time as true ), since the variable album is local to the function it's always undefined when you enter the if body, because its scope is the function load , so it " dies " every time the end of load 's body is reached.

Amith George provides the correct solution to your problem: define the variable album at one scope level higher (ie the level of the object you pass as argument to the extend method)

EDIT

Re-reading the code, assuming controller is a valid instance and exists, and assuming that the controller.collectionInitialized is set to true, you are basically calling a method trigger on a variable album whose value is null.

Using JS hoisting rules, your load function could have be written as

load: function(albumID) {

    var album = null;

    if (controller.collectionInitialized == true) {
        console.log("RESET");
        album.trigger("clear");
    }

    album = new Album([], { title: albumID });
    controller.trigger("collectionInit");
    controller.trigger("switchAlbum", albumID);
}

Maybe, the above re-writing makes it clear that even if controller.collectionInitialized is true , album is a local variable and is always reset to null each time the load function is called.

What ever mechanism you used to enable global access to controller , use the same means to enable global access to album . Do not re-declare album as local to the function.

...

It may help to read more about Javascript variable and function hoisting .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM