Skip to content

Instantly share code, notes, and snippets.

@ryexley
Created September 11, 2012 12:45
Show Gist options
  • Save ryexley/3698163 to your computer and use it in GitHub Desktop.
Save ryexley/3698163 to your computer and use it in GitHub Desktop.
(function(c, api, util) {
c.FilterableCollection = function (collection) {
var filtered = new collection.constructor();
// Expects an object/hash argument that looks like the following example:
// criteria : { value : 'stringToSearchFor', fields : ['field1', 'field2'] }
filtered.filterLike = function (criteria) {
var items;
var match;
if (criteria && Util.GetType(criteria) === 'object') {
items = _.filter(collection.models, function (item) {
for (var i = 0; i < criteria.fields.length; i += 1) {
var field = item.get(criteria.fields[i]);
var pattern = new RegExp(criteria.value, 'i');
match = field.match(pattern);
}
if (match) return item;
});
} else {
items = collection.models;
}
filtered.reset(items);
};
filtered.clearFilter = function () {
filtered.reset(collection.models);
};
collection.on('reset', function () {
filtered.reset(collection.models);
});
return filtered;
}
c.SortableCollection = Backbone.Collection.extend({
initialize : function () {
_.bindAll(this);
},
sortInfo : [],
comparator : function (a, b) {
for (i = 0; i < this.sortInfo.length; i++) {
var criteria = this.sortInfo[i];
var p1 = a.get(criteria.property);
var p2 = b.get(criteria.property);
if (p1 < p2) {
return (-1 * criteria.order);
}
if (p1 > p2) {
return (1 * criteria.order);
}
}
return 0;
},
sortBy : function (property) {
var newSort = [];
_.each(this.sortInfo, function (field) {
if (field.property === property) {
newSort.push({ property : field.property, order : field.order * -1 });
}
});
_.each(this.sortInfo, function (field) {
if (field.property !== property) {
newSort.push({ property : field.property, order : field.order });
}
});
this.sortInfo = newSort;
this.sort();
}
});
c.DocumentBinCollection = c.SortableCollection.extend({
url: function () {
return api.Resources.GetBins;
},
sortInfo : [
// { property : 'SortKey', order : 1 },
{ property : 'DocumentCount', order : -1 },
{ property : 'Name', order : 1 }
]
});
}(Docr.Collections, Docr.Api, Util));

I can create an instance of a Backbone.Collection in a Google Chrome dev tools instance, and pass it an array, call FilterableCollection on it, and then call filterLike, and it runs without any problems, and filters as expected. Everything runs fine.

But when I run this in my app, and an instance of a SortableCollection is created, and then, in the view, as you can see, I'm calling FilterableCollection on it, but when I call filterLike on the resulting collection, it always returns an empty collection, because "collection.models" inside the filterLike method is always empty. Somehow, for some reason, it seems the base collection is always getting reset somewhere...and I can't find it anywhere. I've tried everything I can think of, but I can't for the life of me figure out what's going wrong or what I'm missing.

Can you spot anything? What am I doing wrong?

(function(r, m, v, c) {
r.Main = Backbone.Router.extend({
routes : {
'bin-sort': 'binSort',
'*path' : 'home'
},
home: function() {
new v.HomePage();
},
binSort: function() {
new v.DocumentBinListView({ collection: new c.DocumentBinCollection() });
new m.UnknownDocumentNavigator();
Docr.trigger('docr:set-page-history-collection', new c.BinSortActionHistory());
}
});
}(Docr.Routers, Docr.Models, Docr.Views, Docr.Collections));
(function(m, v, c, api) {
v.DocumentBinListView = Backbone.View.extend({
el: "#document-action-panel",
template: Handlebars.compile($('#pre-sort-actions-template').html() || ''),
listTemplate : Handlebars.compile($('#bin-sort-bin-list-template').html() || ''),
filterCriteriaInputEl : {},
binListEl : {},
events : {
'click .donor-corp-bin' : 'addDocumentToBin',
'click .add-bin' : 'addBin',
'click .view-bins-list' : 'viewBinsList',
'click .view-bins-compact' : 'viewBinsCompact',
'click .refresh-bins' : 'refresh',
'click .edit-bin' : 'editBin',
'click #sort-alpha' : 'sortBins',
'click #sort-count' : 'sortBins',
'keyup #filter-criteria-input' : 'applyFilter',
'scroll' : 'setToolbarPosition'
},
initialize : function () {
_.bindAll(this);
this.initializeKeyboardShortcuts();
this.initializeCollection();
this.render();
this.filterCriteriaInputEl = this.$el.find('#filter-criteria-input');
this.binListEl = this.$el.find('#donor-corp-bins');
$(window).on('resize', this.setToolbarPosition);
Docr.on('docr:bin-changed', this.handleBinChanged);
Docr.on('docr:bin-added', this.handleBinAdded);
Docr.on('docr:bin-sort:bin-list-sort-changed', this.applySort);
},
initializeCollection : function () {
this.collection = c.FilterableCollection(this.collection);
this.collection.bind('reset', this.renderList);
this.collection.fetch();
},
initializeKeyboardShortcuts : function () {
Mousetrap.bind('b+r', this.refresh);
Mousetrap.bind('b+c', this.viewBinsCompact);
Mousetrap.bind('b+l', this.viewBinsList);
},
remove : function () {
$(window).off('resize', this.setToolbarPosition);
},
render: function (items) {
this.$el.html(this.template({}));
this.setToolbarPosition();
return this;
},
renderList : function (items) {
var list = this.listTemplate(this.collection.toJSON());
this.binListEl.html(list).fadeIn(this.animateBinDocumentCount);
},
animateBinDocumentCount : function () {
var targetEl = this.$el.find('.document-count');
var fromColor = '#000';
var toColor = targetEl.css('color');
targetEl
.css({ 'color' : fromColor }) // set it to the highlight color
.stop(true, true) // stop any existing/running animations
.animate({ 'color' : fromColor }, 15000) // hold it at the highlight color for 15 seconds
.animate({ 'color' : toColor }, 5000, function () { // fade out to original color
$(this).removeAttr('style'); // remove the style attribute attached to the element
});
},
handleBinAdded : function (bin) {
this.refresh();
},
handleBinChanged : function (bin) {
this.refresh();
},
addDocumentToBin : function (e) {
Docr.trigger('bin-sort:bin:clicked', $(e.currentTarget));
},
editBin : function (e) {
e.stopPropagation();
// var targetBin = _.find(this.collection.models, function (bin) {
// return bin.get('Name') === $(e.currentTarget).parent().data('id');
// });
var targetBin = this.collection.get($(e.currentTarget).parent().data('id'));
new v.BinEditView({
model : targetBin,
action : $(e.currentTarget).data('bin-action'),
method : $(e.currentTarget).data('save-method')
});
},
addBin : function (e) {
new v.BinEditView({
model : new m.Bin({ url : api.Resources.AddBin }),
action : $(e.currentTarget).data('bin-action'),
method : $(e.currentTarget).data('save-method')
});
},
viewBinsList : function (e) {
this.$el.find('.donor-corp-bins').removeClass('compact');
},
viewBinsCompact : function (e) {
this.$el.find('.donor-corp-bins').addClass('compact');
},
setToolbarPosition : function (e) {
var toolbar = this.$el.find('.bin-actions-toolbar');
var offset = this.$el.offset();
var height = this.$el.height();
toolbar.css({
'position' : 'fixed',
'left' : offset.left,
'top' : (offset.top + height) - toolbar.height(),
'height' : toolbar.height(),
'width' : (this.$el.width() - 17) + 'px'
});
},
refresh : function () {
this.binListEl.fadeOut('fast');
this.collection.fetch();
},
sortBins : function (e) {
e.preventDefault();
var el = $(e.currentTarget);
this.collection.sortBy(el.data('sort-key'));
el.find('.sort-direction')
.toggleClass('font-icon-caret-up')
.toggleClass('font-icon-caret-down');
},
applySort : function () {
// console.log(this.sort.toJSON());
},
applyFilter : function (e) {
e.preventDefault();
var criteria = {
value : this.filterCriteriaInputEl.val(),
fields : ['Name', 'Description']
};
if (criteria.value.length > 0) {
this.collection.filterLike(criteria);
} else {
this.collection.clearFilter();
}
}
});
}(Docr.Models, Docr.Views, Docr.Collections, Docr.Api));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment