Пользовательская директива Angular с фильтром в атрибуте

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

Что-то вроде этого:

<div class="my-module" data="a in array | orFilter:filter"></div>

Где «данные» — это атрибут директивы «мой модуль». Я просмотрел исходный код ngRepeat, но они анализируют аргумент ng-repeat, а затем оценивают его. Я не могу использовать ng-repeat, потому что я создаю новый экземпляр объекта (маркер для карты) из параметра данных.

Неужели так тяжело? Возможно ли это сделать в пользовательской директиве и как?

Небольшой пример того, что я хочу: http://jsfiddle.net/PjRAr/1/

ИЗМЕНИТЬ

Я пытаюсь расширить эту обертку карты для отображения отфильтрованных маркеров.

Мое потенциальное решение - копировать все маркеры и видимые маркеры. Добавьте $watch в фильтр и, когда фильтр будет изменен, вызовите $scope.markers = $scope.$eval("allMarkers | orFilter:filter");.

С этим решением нам нужно хранить две копии всех маркеров (~ 500).


person Petr B.    schedule 07.06.2013    source источник


Ответы (3)


Вы можете $eval использовать выражение фильтра.

в вашей директивной функции ссылки:

elem.text( scope.$eval( attrs.data ).join(', ') );

в вашем шаблоне:

<div my-directive data="['Hello', 'xxx', 'World'] | filter:'o'"></div>

и директива преобразуется (путем фильтрации «xxx») в:

Hello, World

ИЗМЕНИТЬ:

Если значения динамические, вы, конечно, можете сделать:

scope.$watch( attrs.data, function( arr ) {
  elem.text( arr.join(', ') );
});

Я не думаю, что вы можете избежать $watch.

person Tosh    schedule 07.06.2013
comment
Хорошее решение, но не для меня. Сначала ему нужен жестко закодированный массив в атрибуте данных и параметре фильтра (из-за видимости области видимости). Далее мне нужен атрибут данных $watch для изменения. - person Petr B.; 07.06.2013
comment
Ваше решение так близко, но у меня есть классическая проблема с Watchers, запущенными в последних 5 итерациях, пытающихся добавить $$hash в коллекцию, но все равно ничего. играть с моделью - person Petr B.; 07.06.2013
comment
Я думаю, что двусторонняя привязка между родительской областью и вызывающей ее директивой. Если вы используете подход attrs.data (который представляет собой одностороннюю привязку), проблемы возникнуть не должно. - person Tosh; 07.06.2013

Я думаю, вы смешиваете несколько вещей. Я не уверен, почему вы не хотите использовать ng-repeat, для этого он и создан. Поскольку вы изолируете область, у вас нет доступа к родительской области. Привязка '=' пытается привязать атрибут данных изолированной области к модели родительской области, называемой тем, что находится в атрибуте, но вы не можете привязаться к тому, что было отфильтровано. Если вы не хотите повторять div с атрибутами, поместите их в свой собственный элемент, он просто создаст контент...

Вот скрипт, показывающий использование ng-repeat. Вы можете видеть, что привязка двусторонняя, она добавляет свойство updated: true.

(FIDDLE)

    link: function (scope, element, attrs, ctrl) {
        element.append('<p>a: ' + scope.data.a + ', b: ' + scope.data.b);
        scope.data.updated = true;
    }
person Jason Goemaat    schedule 07.06.2013
comment
ng-repeat используется (мной) для визуализации элемента с использованием html или подобного. Я не могу показать данные напрямую. У меня есть модель для связи со сторонним рендерером, где я могу размещать только объекты с данными. Что-то вроде этого играть с моделью. - person Petr B.; 07.06.2013
comment
Не уверен, что директива - лучший способ сделать это, какой смысл иметь ее в вашем HTML, а не просто использовать javascript? - person Jason Goemaat; 07.06.2013
comment
Посмотрите на мое редактирование вопроса. Я пытаюсь расширить оболочку карты для отображения отфильтрованных маркеров. Я решил это ужасным взломом, но пока он работает. Спасибо за помощь. - person Petr B.; 07.06.2013

Итак, когда я использую одностороннюю привязку, я получаю пустой массив в $watch (я думаю, он пытается оценить в локальной области [удалены «данные» из области действия директивы для односторонней привязки]. Когда я использую двустороннюю привязку [в области действия директивы {data: "=data"}] я получил ошибку "Наблюдатели сработали за последние 5 итераций" (это распространенная ошибка для фильтрации в angular).

Итак, мое решение:

Директива:

...
scope: {
  data: "=data"
}
...
link: function (scope, element, attrs, ctrl) {
  ...
  scope.$watch("data", function (newValue) {
    angular.forEach(newValue, function (v, i) {
      model.add(v);
    }
  }
}
...

Контроллер:

  ...
  $scope.filter = { a:true, b:false, ... };
  $scope.all = [..data..];
  $scope.visible = [..data..];    

  $scope.$watch("filter", function(newValue) {    
    $scope.visible = $scope.$eval("all | orFilter:filter"); 
  }, true);
  ...

HTML:

<div my-module data="visible"></div>

Большое спасибо, ребята, вы мне очень помогаете. Я узнал много нового об угловом связывании.

person Petr B.    schedule 07.06.2013