Yehuda
Yehuda

Reputation: 1382

Angularjs - Enumerate objects in template

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

Answers (3)

PzYon
PzYon

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

Matt Ball
Matt Ball

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

Moncef Hassein-bey
Moncef Hassein-bey

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

Related Questions