Show an aggregated list in angularjs

后端 未结 2 2051
野性不改
野性不改 2020-12-30 05:24

In my model I have data similar to:

$scope.list = [{id:0,tags:[\'tag1\',\'tag2\']},{id:2,tags:[\'tag2\']}};

I want to show a list of tags (

相关标签:
2条回答
  • 2020-12-30 06:29

    Use a custom filter to get a unique set/array of tags, suitable for use with ng-repeat:

    .filter('uniqueTags', function() {
        return function(list) {
            var tags = {};
            angular.forEach(list, function(obj, key) {
                angular.forEach(obj.tags, function(value) {
                    tags[value] = 1;
                })
            });
            var uniqueTags = []
            for (var key in tags) {
                uniqueTags.push(key);
            }
            return uniqueTags;
        }
    });
    

    I first put the tags into an object, which automatically gives us uniqueness. Then I convert it to an array.

    Use as follows:

    <div ng-repeat="tag in list | uniqueTags">
    

    Fiddle.


    The following may not do what I think you probably want/expect it to do:

    <input type="checkbox" ng-model="filter.tag">
    

    This does not create $scope properties filter.tag1 and filter.tag2 on the controller scope (i.e., the scope where ng-repeat is used). Each iteration of ng-repeat creates its own child scope, so the ng-model above will create scope property filter.tag on each ng-repeat child scope, as shown in my fiddle.

    0 讨论(0)
  • 2020-12-30 06:30

    You are looking to perform three operations:

    • Get the array of tags from each item in $scope.list
    • Flatten these into a single array
    • Get the unique values from this array

    You can do this with pure JavaScript, but to make things easier, I would recommend using Underscore, a library that gives you access to many functions for manipulating and inspecting arrays, objects, and so forth.

    Let's start with this code:

    $scope.list = [
      {id: 0, tags: ['tag1', 'tag2']},
      {id: 1, tags: ['tag2']},
      {id: 2, tags: ['tag1', 'tag3', 'tag4']},
      {id: 3, tags: ['tag3', 'tag4']}
    ];
    

    Now, let's perform the first operation: get the array from the tags property for each object in $scope.list. Underscore provides the pluck method, which is just what we need.

    pluck _.pluck(list, propertyName)

    A convenient version of what is perhaps the most common use-case for map: extracting a list of property values.

    Using pluck, we can get the following:

    var tags = _.pluck($scope.list, 'tags');
    // gives us [['tag1', 'tag2'], ['tag2'], ['tag1', 'tag3', 'tag4'], ['tag3', 'tag4']]
    

    Now, we want to flatten that array.

    flatten _.flatten(array, [shallow])

    Flattens a nested array (the nesting can be to any depth). If you pass shallow, the array will only be flattened a single level.

    tags = _.flatten(tags);
    // gives us ['tag1', 'tag2', 'tag2', 'tag1', 'tag3', 'tag4', 'tag3', 'tag4']
    

    Finally, you only want one instance of each tag.

    uniq _.uniq(array, [isSorted], [iterator]) Alias: unique

    Produces a duplicate-free version of the array, using === to test object equality. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iterator function.

    tags = _.unique(tags)
    // gives us ['tag1', 'tag2', 'tag3', 'tag4']
    

    We can combine these together with Underscore's useful chain method to chain these together. Let's create a function on the scope that returns the unique tags:

    $scope.uniqueTags = function() {
      return _.chain($scope.list)
        .pluck('tags')
        .flatten()
        .unique()
        .value();
    };
    

    Since this is a function, it will always return the unique tags, no matter if we add or remove items in $scope.list after the fact.

    Now you can use ng-repeat on uniqueTags to show each tag:

    <div ng-repeat="tag in uniqueTags()">
      <label class="checkbox">
        <input type="checkbox" ng-model="filter.tag" />
        {{tag}}
      </label>
    </div>
    

    Here is a working jsFiddle that demonstrates this technique: http://jsfiddle.net/BinaryMuse/cqTKG/

    0 讨论(0)
提交回复
热议问题