Reputation: 1382
I have two services, Location and Category.
Each location can be connected to one or more locations.. Location's category is store as array of categories id's, for example:
Locations: [{id: 1,
name: "NJ",
locations: [0, 2, 3]
},{
id: 2,
name: "NY",
location: [0, 2]
}]
Categories: [{
id: 0,
name: "Cities"
}, {
id: 2,
name: "Canyons"
}, {
id: 3,
name: "Work"
}]
Now, I want in my template to enumerate the categories of each location by it's name with a comma like:
NJ categories: Cities, Canyons, Work.
NY categories: Cities, Work.
My code inject the two services (Location and Category) into the controller and each of the services have "getAll()" function that return array of all it's objects..
What is the right way to do it?
Maybe I can put it on directive?
Thanks :)
Upvotes: 0
Views: 283
Reputation: 2993
How about this? It's a simple implementation (all in one HTML, as I don't know what you're application components look like) using a directive. It works, there's definitely room for improvement though.. But it should be enough to get the hang of it.
Please note that the services you mentioned are not implemented, I just expose the data on the controller and pass it to the directive. You could do the same with the data from your service or inject the services in your directive:
<html>
<head>
<script type="text/javascript" src="http://code.angularjs.org/1.4.6/angular.js"></script>
<script type="text/javascript">
var geoApp = angular.module("geography", []);
geoApp.controller("geographyController", function () {
this.locations = [
{
id: 1,
name: "NJ",
categories: [0, 2, 3]
}, {
id: 2,
name: "NY",
categories: [0, 2]
}
];
this.categories =
[
{
id: 0,
name: "Cities"
}, {
id: 2,
name: "Canyons"
}, {
id: 3,
name: "Work"
}
];
});
geoApp.directive("categoriesFor", function () {
var link = function (scope) {
var getCategoryName = function (id) {
for (var i = 0; i < scope.categories.length; i++) {
var category = scope.categories[i];
if (category.id === id) {
return category.name;
}
}
return "not available (" + id + ")";
};
scope.getCategoriesForLocation = function () {
var availableCategories = [];
angular.forEach(scope.location.categories, function (categoryId) {
availableCategories.push(getCategoryName(categoryId));
});
return availableCategories.join(scope.splitChar);
}
};
return {
restrict: "A",
scope: {
location: "=categoriesFor",
categories: "=",
splitChar: "="
},
template: "{{location.name}} categories: {{getCategoriesForLocation()}}",
link: link
};
});
</script>
</head>
<body data-ng-app="geography" data-ng-controller="geographyController as geo">
<ul>
<li data-ng-repeat="location in geo.locations">
<span data-categories-for="location"
data-categories="geo.categories"
data-split-char="', '"></span>
</li>
</ul>
</body>
</html>
One improvement might be in changing your data structure, i.e. making objects (instead of arrays) where the key is the id. That would make it easier to access them.
And, as always with Angular, there are several different approaches. It always depends and your needs (i.e. re-usability, etc.).
Upvotes: 0
Reputation: 422
I'd say the easiest way to achieve this is to build up a third array with the Strings that you want to display and then use an ng-repeat
to display them on your page.
So in your controller, you'd have something like (note the map and filter functions will only work in modern browsers):
var locs = Locations.getAll()
var cats = Categories.getAll()
$scope.display = locs.map(function(loc) {
return loc.name + ' categories: ' + loc.locations.map(function(id) {
return cats.filter(function(cat) {
return id === cat.id;
})[0].name;
});
});
And on your page, you'd have:
<ul>
<li ng-repeat="line in display">{{line}}</li>
</ul>
Upvotes: 0
Reputation: 1361
What is the right way to do it?
You could use ngRepeat directive + custom filter.
<span ng-repeat="city in cities">{{ categories | CategoriesInCity:city }}</span>
Filter :
myApp.filter('CategoriesInCity', function(){
return function(categories , city){
// build categoriesStringFound
return city+'categories'+categoriesStringFound;
}
})
Upvotes: 0