Angular custom directive with filter in attribute

10,023

Solution 1

So, when I use one-way binding i got empty array in $watch (i think it's trying evaluate in local scope [removed "data" from directive scope for one way binding]. When i use two way binding [in directive scope is {data: "=data"}] i got error "Watchers fired in the last 5 iterations" (it's common error for filtering in angular).

So my solution:

Directive:

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

Controller:

  ...
  $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>

Thank you very much guys, you're help me so much. I'm learned many new things about angular binding.

Solution 2

You can $eval the filter expression.

in your directive link function:

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

in your template:

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

and the directive renders (by filtering-out 'xxx') to:

Hello, World

EDIT:

If the values are dynamic, you can of course do:

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

I do not think you can avoid having $watch, though.

Share:
10,023
Petr B.
Author by

Petr B.

Updated on June 04, 2022

Comments

  • Petr B.
    Petr B. almost 2 years

    I would like make angular directive where I use filter on data which are passed as argument.

    So something like this:

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

    Where "data" is attribute of directive "my-module". I looked into ngRepeat source, but they parse ng-repeat argument and then they evaluate them. I can't use ng-repeat because I'm creating new instance of object (Marker for map) from data parameter.

    Is it realy so hard? Is possible do this in custom directive and how?

    Small example what i want: http://jsfiddle.net/PjRAr/1/

    EDIT

    I'm trying extend this map wrapper to render filtered markers.

    My potencional solution is holding copy of all markers and visible markers. Add $watch to filter and when filter was changed call $scope.markers = $scope.$eval("allMarkers | orFilter:filter");.

    With this solution we need hold two copy of all markers (~500).