-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Works in a similar way to the SortableMixin. Mix this into an ArrayProxy, define the filterProperties and the array will be filtered to only include the objects whose filterProperties are truthy. You can get more advanced filtering by defining a custom filterCondition. The filterCondition is used to determine if the object is to be included in the filtered list. Any item properties used in the filterCondition will need to be lised in filterProperties.
- Loading branch information
Showing
3 changed files
with
320 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach; | ||
|
||
/** | ||
@class | ||
@extends Ember.Mixin | ||
@extends Ember.MutableEnumerable | ||
*/ | ||
Ember.FilterableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { | ||
filterProperties: null, | ||
|
||
filterCondition: function(item){ | ||
var filterProperties = get(this, 'filterProperties'); | ||
return Ember.A(filterProperties).every(function(property){ | ||
return !!get(item, property); | ||
}); | ||
}, | ||
|
||
addObject: function(obj) { | ||
var content = get(this, 'content'); | ||
content.pushObject(obj); | ||
}, | ||
|
||
removeObject: function(obj) { | ||
var content = get(this, 'content'); | ||
content.removeObject(obj); | ||
}, | ||
|
||
destroy: function() { | ||
var content = get(this, 'content'), | ||
filterProperties = get(this, 'filterProperties'); | ||
|
||
if (content && filterProperties) { | ||
forEach(content, function(item) { | ||
forEach(filterProperties, function(filterProperty) { | ||
Ember.removeObserver(item, filterProperty, this, 'contentItemFilterPropertyDidChange'); | ||
}, this); | ||
}, this); | ||
} | ||
|
||
return this._super(); | ||
}, | ||
|
||
isFiltered: Ember.computed('filterProperties', function() { | ||
return !!get(this, 'filterProperties'); | ||
}), | ||
|
||
arrangedContent: Ember.computed('content', 'filterProperties.@each', function(key, value) { | ||
var content = get(this, 'content'), | ||
isFiltered = get(this, 'isFiltered'), | ||
filterProperties = get(this, 'filterProperties'), | ||
filterValue = get(this, 'filterValue'), | ||
self = this; | ||
|
||
if (content && isFiltered) { | ||
forEach(content, function(item) { | ||
forEach(filterProperties, function(filterProperty) { | ||
Ember.addObserver(item, filterProperty, this, 'contentItemFilterPropertyDidChange'); | ||
}, this); | ||
}, this); | ||
content = content.slice(); | ||
content = content.filter(this.filterCondition, this); | ||
|
||
return Ember.A(content); | ||
} | ||
|
||
return content; | ||
}).cacheable(), | ||
|
||
_contentWillChange: Ember.beforeObserver(function() { | ||
var content = get(this, 'content'), | ||
filterProperties = get(this, 'filterProperties'); | ||
|
||
if (content && filterProperties) { | ||
forEach(content, function(item) { | ||
forEach(filterProperties, function(filterProperty) { | ||
Ember.removeObserver(item, filterProperty, this, 'contentItemFilterPropertyDidChange'); | ||
}, this); | ||
}, this); | ||
} | ||
|
||
this._super(); | ||
}, 'content'), | ||
|
||
contentArrayWillChange: function(array, idx, removedCount, addedCount) { | ||
var isFiltered = get(this, 'isFiltered'); | ||
|
||
if (isFiltered) { | ||
var arrangedContent = get(this, 'arrangedContent'); | ||
var removedObjects = array.slice(idx, idx+removedCount); | ||
var filterProperties = get(this, 'filterProperties'); | ||
|
||
forEach(removedObjects, function(item) { | ||
arrangedContent.removeObject(item); | ||
forEach(filterProperties, function(filterProperty) { | ||
Ember.removeObserver(item, filterProperty, this, 'contentItemFilterPropertyDidChange'); | ||
}, this); | ||
}); | ||
} | ||
|
||
return this._super(array, idx, removedCount, addedCount); | ||
}, | ||
|
||
contentArrayDidChange: function(array, idx, removedCount, addedCount) { | ||
var isFiltered = get(this, 'isFiltered'), | ||
filterProperties = get(this, 'filterProperties'); | ||
|
||
if (isFiltered) { | ||
var addedObjects = array.slice(idx, idx+addedCount); | ||
var arrangedContent = get(this, 'arrangedContent'); | ||
|
||
forEach(addedObjects, function(item) { | ||
this.insertItemFiltered(item); | ||
|
||
forEach(filterProperties, function(filterProperty) { | ||
Ember.addObserver(item, filterProperty, this, 'contentItemFilterPropertyDidChange'); | ||
}, this); | ||
}, this); | ||
} | ||
|
||
return this._super(array, idx, removedCount, addedCount); | ||
}, | ||
|
||
contentItemFilterPropertyDidChange: function(item) { | ||
var arrangedContent = get(this, 'arrangedContent'), | ||
index = arrangedContent.indexOf(item); | ||
|
||
arrangedContent.removeObject(item); | ||
this.insertItemFiltered(item); | ||
}, | ||
|
||
insertItemFiltered: function(item){ | ||
var arrangedContent = get(this, 'arrangedContent'); | ||
|
||
if( this.filterCondition(item) ){ | ||
arrangedContent.pushObject(item); | ||
} | ||
} | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
var get = Ember.get, set = Ember.set; | ||
|
||
|
||
var array, unfilteredArray, filteredArrayController; | ||
|
||
module("Ember.Filterable"); | ||
|
||
module("Ember.Filterable with content", { | ||
setup: function() { | ||
Ember.run(function() { | ||
array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; | ||
unfilteredArray = Ember.A(array); | ||
|
||
filteredArrayController = Ember.ArrayProxy.create(Ember.FilterableMixin, { | ||
content: unfilteredArray | ||
}); | ||
}); | ||
}, | ||
|
||
teardown: function() { | ||
Ember.run(function() { | ||
filteredArrayController.set('content', null); | ||
filteredArrayController.destroy(); | ||
}); | ||
} | ||
}); | ||
|
||
test("if you do not specify `filterProperties` filterable has no effect", function() { | ||
equal(filteredArrayController.get('length'), 3, 'array has 3 items'); | ||
|
||
unfilteredArray.pushObject({id: 4, name: 'Scumbag Chavard'}); | ||
|
||
equal(filteredArrayController.get('length'), 4, 'array has 4 items'); | ||
}); | ||
|
||
test("you can change the filterProperties and filterCondition", function() { | ||
equal(filteredArrayController.get('length'), 3, 'precond - array has 3 items'); | ||
|
||
filteredArrayController.filterCondition = function(item){ return get(item, 'id') === 1; }; | ||
filteredArrayController.set('filterProperties', ['id']); | ||
|
||
equal(filteredArrayController.get('length'), 1, 'array has 1 item'); | ||
equal(filteredArrayController.objectAt(0).name, 'Scumbag Dale', 'array is filtered by id'); | ||
}); | ||
|
||
|
||
module("Ember.Filterable with content, filterProperties and filterCondition", { | ||
setup: function() { | ||
Ember.run(function() { | ||
array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; | ||
unfilteredArray = Ember.A(array); | ||
|
||
filteredArrayController = Ember.ArrayProxy.create(Ember.FilterableMixin, { | ||
content: unfilteredArray, | ||
filterProperties: ['id'], | ||
filterCondition: function(item){ return get(item, 'id') === 1; } | ||
}); | ||
}); | ||
}, | ||
|
||
teardown: function() { | ||
Ember.run(function() { | ||
filteredArrayController.destroy(); | ||
}); | ||
} | ||
}); | ||
|
||
test("filtered object will expose filtered content", function() { | ||
equal(filteredArrayController.get('length'), 1, 'array is filtered by id'); | ||
equal(filteredArrayController.objectAt(0).name, 'Scumbag Dale', 'the object is the correct one'); | ||
}); | ||
|
||
test("you can add objects in the filtered array", function() { | ||
equal(filteredArrayController.get('length'), 1, 'array has 1 item'); | ||
|
||
unfilteredArray.pushObject({id: 1, name: 'Scumbag Chavard'}); | ||
|
||
equal(filteredArrayController.get('length'), 2, 'array has 2 items'); | ||
equal(filteredArrayController.objectAt(1).name, 'Scumbag Chavard', 'a new object added to content was inserted according to given constraint'); | ||
|
||
unfilteredArray.addObject({id: 1, name: 'Scumbag Fucs'}); | ||
|
||
equal(filteredArrayController.get('length'), 3, 'array has 3 items'); | ||
equal(filteredArrayController.objectAt(2).name, 'Scumbag Fucs', 'a new object added to controller was inserted according to given constraint'); | ||
}); | ||
|
||
test("new objects don't get added if they don't meet the filter condition", function() { | ||
equal(filteredArrayController.get('length'), 1, 'array has 1 item'); | ||
|
||
unfilteredArray.pushObject({id: 5, name: 'Scumbag Chavard'}); | ||
|
||
equal(filteredArrayController.get('length'), 1, 'array has 1 item'); | ||
}); | ||
|
||
test("you can change a filter property and the content will be removed", function() { | ||
equal(filteredArrayController.get('length'), 1, 'array has 1 item'); | ||
equal(filteredArrayController.objectAt(0).name, 'Scumbag Dale', 'dale is the only one'); | ||
|
||
set(filteredArrayController.objectAt(0), 'id', 2); | ||
|
||
equal(filteredArrayController.get('length'), 0, 'array has no items'); | ||
}); | ||
|
||
test("you can change a filter property and the content will be added", function() { | ||
equal(filteredArrayController.get('length'), 1, 'array has 1 item'); | ||
equal(filteredArrayController.objectAt(0).name, 'Scumbag Dale', 'dale is the only one'); | ||
|
||
set(unfilteredArray.objectAt(1), 'id', 1); | ||
|
||
equal(filteredArrayController.get('length'), 2, 'array has two items'); | ||
equal(filteredArrayController.objectAt(0).name, 'Scumbag Dale', 'dale is there'); | ||
equal(filteredArrayController.objectAt(1).name, 'Scumbag Katz', 'katz is there'); | ||
}); | ||
|
||
module("Ember.Filterable with filterProperties and filterCondition", { | ||
setup: function() { | ||
Ember.run(function() { | ||
array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; | ||
unfilteredArray = Ember.A(array); | ||
|
||
filteredArrayController = Ember.ArrayProxy.create(Ember.FilterableMixin, { | ||
filterProperties: ['id'], | ||
filterCondition: function(item){ | ||
return get(item,'id') === 1; | ||
} | ||
}); | ||
}); | ||
}, | ||
|
||
teardown: function() { | ||
Ember.run(function() { | ||
filteredArrayController.destroy(); | ||
}); | ||
} | ||
}); | ||
|
||
test("you can set content later and it will be filtered", function() { | ||
equal(filteredArrayController.get('length'), 0, 'array has 0 items'); | ||
|
||
Ember.run(function() { | ||
filteredArrayController.set('content', unfilteredArray); | ||
}); | ||
|
||
equal(filteredArrayController.get('length'), 1, 'array has 1 item'); | ||
equal(filteredArrayController.objectAt(0).name, 'Scumbag Dale', 'dale is in the filtered array'); | ||
}); | ||
|
||
module("Ember.Filterable with content and filterProperties", { | ||
setup: function() { | ||
Ember.run(function() { | ||
array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: null }]; | ||
unfilteredArray = Ember.A(array); | ||
|
||
filteredArrayController = Ember.ArrayProxy.create(Ember.FilterableMixin, { | ||
content: unfilteredArray, | ||
filterProperties: ['id', 'name'] | ||
}); | ||
}); | ||
}, | ||
|
||
teardown: function() { | ||
Ember.run(function() { | ||
filteredArrayController.destroy(); | ||
}); | ||
} | ||
}); | ||
|
||
test("by default it tests if all filterProperties are truthy", function() { | ||
equal(filteredArrayController.get('length'), 2, 'array has 2 items'); | ||
|
||
unfilteredArray.pushObject({id: 4, name: 'Scumbag Chavard'}); | ||
|
||
equal(filteredArrayController.get('length'), 3, 'adds valid items to the filtered array'); | ||
|
||
unfilteredArray.pushObject({id: undefined, name: 'Scumbag Chavard'}); | ||
unfilteredArray.pushObject({id: 6, name: ''}); | ||
|
||
equal(filteredArrayController.get('length'), 3, "it doesn't add invalid items to the filtered array"); | ||
}); |