Показывать агрегированный список в angularjs - программирование

Показывать агрегированный список в angularjs

В моей модели у меня есть данные, похожие на:

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

Я хочу показать список тегов (содержит уникальные значения "tag1" и "tag2" ) с помощью флажков. Надеюсь, что-то вроде:

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

Я знаю, как фильтровать основной список на основе того, что было проверено, если я жестко кодирую список, но не как автоматически создать список уникальных тегов.

4b9b3361

Ответ 1

Вы хотите выполнить три операции:

  • Получить массив тегов из каждого элемента в $scope.list
  • Сгладить их в один массив
  • Получить уникальные значения из этого массива

Вы можете сделать это с помощью чистого JavaScript, но чтобы упростить задачу, я бы рекомендовал использовать Underscore библиотеку, которая дает вам доступ ко многим функциям для манипулирования и проверка массивов, объектов и т.д.

Начните с этого кода:

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

Теперь позвольте выполнить первую операцию: получить массив из свойства tags для каждого объекта в $scope.list. Подчеркивание предоставляет метод pluck, который нужен именно нам.

pluck _.pluck(list, propertyName)

Удобная версия, пожалуй, наиболее распространенного случая использования для карты: извлечение списка значений свойств.

Используя pluck, мы можем получить следующее:

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

Теперь мы хотим сгладить этот массив.

сгладить _.flatten(array, [shallow])

Сглаживает вложенный массив (вложенность может быть любой глубиной). Если вы пройдете неглубоко, массив будет только сплющен на один уровень.

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

Наконец, вам нужен только один экземпляр каждого тега.

uniq _.uniq(array, [isSorted], [iterator]) Псевдоним: unique

Производит дублируемую версию массива, используя === для проверки равенства объектов. Если вы заранее знаете, что массив отсортирован, передача true для isSorted будет выполнять гораздо более быстрый алгоритм. Если вы хотите вычислить уникальные элементы на основе преобразования, передайте функцию итератора.

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

Мы можем объединить их вместе с Underscore полезным методом chain, чтобы связать их вместе. Позвольте создать функцию в области, которая возвращает уникальные теги:

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

Так как это функция, она всегда будет возвращать уникальные теги, независимо от того, добавим или удалим элементы в $scope.list после факта.

Теперь вы можете использовать ng-repeat на uniqueTags, чтобы показать каждый тег:

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

Вот рабочий jsFiddle, демонстрирующий эту технику: http://jsfiddle.net/BinaryMuse/cqTKG/

Ответ 2

Используйте специальный фильтр, чтобы получить уникальный набор/массив тегов, подходящий для использования с 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;
    }
});

Я сначала помещаю теги в объект, который автоматически дает нам уникальность. Затем я преобразую его в массив.

Используйте следующее:

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

Fiddle.


Следующие действия могут не делать то, что я думаю, что вы, вероятно, хотите/ожидаете от него:

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

Это не создает свойства $scope filter.tag1 и filter.tag2 в области контроллера (т.е. область, в которой используется ng-repeat). Каждая итерация ng-repeat создает свою собственную дочернюю область, поэтому вышеописанная ng-модель создаст свойство scope filter.tag для каждой дочерней области ng-repeat, как показано на моей скрипке.