I want to filter websites that are in the filtered categories and display them in order of their rank.The code snippet is:
<div ng-repeat="category in categories | filter:{will return more than one category}">
<div ng-repeat="website in websites | orderBy:'rank'| filter:{ parent_id : category.id }:true">
{{website.title}},{{website.rank}}
</div>
</div>
But in the nested loop, since orderby is in inner loop, it works for each iteration of outer loop but the overall result is not sorted according to rank. Say there are three categories and filter gives cat1 &cat2. If websites with rank 6,2,5 are is cat1 and 9,1 in cat2 then the result will be 2,5,6,1,9.I want the result to be 1,2,5,6,9.How should I do that ?
Should I pass the category in some function and write the js code to get the array of filtered website and then sort them and return them to template or is there any other better way to do that in template itself?
I think what you want to do, can not be done as is. Anyway you could use a custom filter.
This approach gives you a category selection mechanism as another example of how you could use this custom filter.
angular.module('app',[])
// categories
.value('categories', [ { id: 0, title:"first" }, { id: 1, title:"second" }, { id: 2, title:"third" } ])
// websites
.value('websites', [ { rank: 3, parent_id: 2, title: "Alice" },
{ rank: 1, parent_id: 1, title: "Bob" },
{ rank: 9, parent_id: 1, title: "Carol" },
{ rank: 2, parent_id: 0, title: "David" },
{ rank: 4, parent_id: 0, title: "Emma" },
{ rank: 5, parent_id: 0, title: "Foo" } ])
// controller,
.controller('ctrl', ['$scope', 'categories', 'websites', function($scope, categories, websites) {
// categories injected
$scope.categories = categories;
// websites injected
$scope.websites = websites;
// categories selection helper, useful for preselection
$scope.selection = { 0: true, 1:false } // 2: false (implicit)
}])
// categories filter, categories injected.
.filter('bycat', ['categories', function(categories) {
// websites is the result of orderBy :'rank', selection helper passed as paramenter.
return function(websites, selection) {
// just an Array.prototype.filter
return websites.filter(function(website) {
// for each category
for(var i=0; i < categories.length; i++) {
var cat = categories[i];
// if category is selected and website belongs to category
if (selection[cat.id] && cat.id == website.parent_id) {
// include this website
return true;
}
}
// exclude this website
return false;
});
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<span ng-repeat="category in categories">
<label class="checkbox" for="{{category.id}}">
<input type="checkbox" ng-model="selection[category.id]" name="group" id="{{category.id}}" />
{{category.title}}
</label>
</span>
<div ng-repeat="website in websites | orderBy:'rank'| bycat: selection">
<p>Rank:{{website.rank}} - {{website.title}} ({{categories[website.parent_id].title}})</p>
</div>
</div>
Se code comments.
angular.module('app',[])
// categories will be injected in custom filter.
.value('categories', [ { id: 1, title:"first" }, { id: 2, title:"second" } ])
.controller('ctrl', function($scope) {
// sample websites
$scope.websites = [ { rank: 1, parent_id: 2, title: "Site w/rank 1" },
{ rank: 9, parent_id: 2, title: "Site w/rank 9" },
{ rank: 2, parent_id: 1, title: "Site w/rank 2" },
{ rank: 4, parent_id: 1, title: "Site w/rank 4" },
{ rank: 5, parent_id: 1, title: "Site w/rank 5" } ];
})
// custom filter, categories injected.
.filter('bycat', ['categories', function(categories) {
// websites is the result of orderBy :'rank'
return function(websites, catText) {
// just an Array.prototype.filter
return websites.filter(function(website) {
// if no filter, show all.
if (!catText) return true;
for(var i=0; i < categories.length; i++) {
var cat = categories[i];
// if matches cat.title and id == parent_id, gotcha!
if (cat.title.indexOf(catText) != -1 && cat.id == website.parent_id) {
return true;
}
}
// else were
return false;
});
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<input type="text" ng-model="filterText">
<p>Try "first" and "second"</p>
<div ng-repeat="website in websites | orderBy:'rank'| bycat: filterText ">
{{website.title}},{{website.rank}}
</div>
</div>