Alexander Beletsky's development blog

My profession is engineering

Baby steps to Backbone.js: Exploring collections. Part 2.

Backbone.js is event-driven framework. All Backbone entities are extended from Backbone.Event object. That means, they are able to raise events, subscribers are able to listen to that events and act accordingly. Let’s take a look what type of event does Backbone.Collection have.

Backbone.Collection events

Will have a test suite for that,

describe('collection events', function () {
    var listener;

    beforeEach(function () {
        collection = new FeedbackCollection();
    });

    beforeEach(function () {
        listener = jasmine.createSpy();
    });
    

Here we are creating collection for testing and Jasmine spy, special function we going to use as event subscriber.

Adding element to collection

As we saw previously there are several ways of adding new elements to collection. By add and push methods. The important thing, does not matter what API method you use, Backbone.Collection would trigger ‘add’ event.

By add method,

describe('while adding elements', function () {
    beforeEach(function () {
        collection.on('add', listener);
    });

    beforeEach(function () {
        collection.add({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
    });

    it ('should raise add event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    

By push method,

describe('while pusing elements', function () {
    beforeEach(function () {
        collection.on('add', listener);
    });

    beforeEach(function () {
        collection.push({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
    });

    it ('should raise add event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    

Each event handlers receives model itself and reference to collection.

Removing elements from collection

Similarly, there 2 ways of removing items from collection, by remove and pop methods.

By remove method,

describe('while removing items', function () {
    beforeEach(function () {
        collection.on('remove', listener);
    });

    beforeEach(function () {
        collection.add({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
        var model = collection.get('feedback-1');
        collection.remove(model);
    });

    it ('should raise remove event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    

By pop method,

describe('while poping items', function () {
    beforeEach(function () {
        collection.on('remove', listener);
    });

    beforeEach(function () {
        collection.add({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
        collection.pop();
    });

    it ('should raise remove event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    

Resetting and sorting

Besides just adding and removing stuff from collection, it have few more method which reaction is triggering event. It’s reset and sort. Reset is the bulk insert into collection, it works great when we fetch some data from server and want to push everything just by one operation. Sort, is rarely called manually, since if collection provides comparator function, it would sort itself, during add or reset operations. But sometimes sorting could be triggered from UI as user changes the sort column of table, for example.

Resetting collection,

describe('while reseting collection', function () {
    beforeEach(function () {
        collection.on('reset', listener);
    });

    beforeEach(function () {
        collection.reset([
            {id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'}]);
    });

    it('should raise reset event', function () {
        expect(listener).toHaveBeenCalled();
    });
});

Sorting collection,

describe('while sorting collection', function () {
    beforeEach(function () {
        collection.on('sort', listener);
    });

    beforeEach(function () {
        collection.reset([
            {id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'}]);
        collection.sort();
    });

    it('should raise sort event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    

Why it matters?

Knowing the events of all Backbone.js entities is very important. You should always design you application based on events triggering/subscription, instead of direct function call. That would make your code much de-coupled and UI logic very flexible.