Reputation: 55
I have a service that manages a set of data. The service is polite enough to provide options to return a subset of said data based on (whatever logic, in this example it's simply going to look for a specific data attribute value). The service will return an array of matches. In my view, I want to bind to this set of matches. However, because the service returns a new array object each time the filter function is called, that doesn't work. My view is bound to the previously returned array object.
Try this fiddle:
var app = angular.module('app', []);
app.factory('MrData', function() {
var allData = [
{name: 'Adam', type: 'boy'},
{name: 'Kassidy', type: 'girl'},
{name: 'Justin', type: 'boy'},
{name: 'Chloe', type: 'cat'},
{name: 'D The P', type: 'dog'},
];
return {
add: function(thing) {
allData.push(thing);
},
fetchAll: function() {
return allData;
},
fetchForType: function(type) {
var some = [];
for (var i = 0; i < allData.length; i++) {
if (allData[i].type == type)
some.push(allData[i]);
}
return some;
}
}
});
app.controller('SomeCtrl', function($scope, MrData) {
$scope.showSome = MrData.fetchForType('boy');
$scope.showAll = MrData.fetchAll();
$scope.addBoy = function() {
MrData.add({name: 'TED!', type: 'boy'});
}
$scope.addOther = function() {
MrData.add({name: 'Other', type: 'Other'});
}
});
and the view:
<div ng-app="app">
<div ng-controller="SomeCtrl">
<button ng-click="addBoy()">Add Boy</button>
<button ng-click="addOther()">Add Other</button>
<h2>Boys</h2>
<ol>
<li ng-repeat="thing in showSome">
{{ thing.type }}
{{ thing.name }}
</li>
</ol>
<h2>All</h2>
<ol>
<li ng-repeat="thing in showAll">
{{ thing.type }}
{{ thing.name }}
</li>
</ol>
</div>
</div>
You can see that the list of boys is not updated when you click Add Boy. And I understand why- but I don't understand how to fix this! Must be a simple design pattern or feature that I just don't know about, or can't figure out on my own.
Thanks you in advance, Adam
Upvotes: 2
Views: 743
Reputation: 52867
You need to reapply the fiters because the bound arrays have not changed when you call addBoy() or addOther().
One way around this is to call the filter after each call:
function applyFilter(){
$scope.showSome = MrData.fetchForType('boy');
$scope.showAll = MrData.fetchAll();
}
$scope.addBoy = function() {
MrData.add({name: 'TED!', type: 'boy'});
applyFilter();
}
$scope.addOther = function() {
MrData.add({name: 'Other', type: 'Other'});
applyFilter();
}
I would show how it could be done with angular filters but it seems someone already has.
Upvotes: 0
Reputation: 33179
You obviously understand what is broken, that your view is bound to two different lists. However, the problem is that you are filtering the model, when you really should be filtering the view. This way you always stay bound to a single list, and the view manages how that list is presented to the user.
What you should be using is a filter https://docs.angularjs.org/api/ng/filter/filter
For example, this simple ng-repeat
should work:
<li ng-repeat="thing in showAll | filter:{type: 'boy'}">
Also updated fiddle
Upvotes: 1