javascriptangularjsangularjs-scopeangularjs-ng-repeatangularjs-ng-transclude

Filtering not working in transcluded DOM content


I am building two AngularJS (version 1.6.5) components and I am not able to get filtering working when I use transclusion.

The first component is a simple container which uses transclusion to populate a <div> content:

app.component('panelWithTitle', {
  template: '<div><h1>{{$ctrl.title}}</h1><div class="content" ng-transclude></div></div>',
  bindings: {
    title: '@'
  },
  require: 'title',
  transclude: true
});

The second component uses the container (<panel-with-title>) and feed it with a simple filtered (from an input field) list:

app.component('mainComponent', {
  controller: function($scope) {
    $scope.allItems = ["10", "100", "200", "42", "1337"];
    // Simple filter function (may be more complicated)
    $scope.filterFunc = function (item) {
      if (!$scope.filterValue) {
        // No value
        return true;
      }
      return item.indexOf($scope.filterValue) !== -1;
    };
  },
  template: '<panel-with-title title="MyTitle">'            // Replace by <div>
      + '<input type="text" ng-model="filterValue">'
      + '<ul><li ng-repeat="item in allItems | filter:filterFunc">{{item}}</li></ul>'
      + '</panel-with-title>'                               // Replace by </div>
});

In that state, the filtering is not working because $scope.filterValue is undefined. Here is a demo Plunkr. I noticed:

What did I make wrong to get it not working? Why $scope.filterValue is undefined while $scope.allItems IS defined?

Thanks.


Solution

  • Your $scope.filterValue always undefined and filter returns true because your template uses different scope.

    So add $root to filterValue like:

    <input type="text" ng-model="$root.filterValue">
    

    and in component use $scope.$parent.filterValue:

    return item.indexOf($scope.$parent.filterValue) !== -1;
    

    Demo Plunker


    BTW, nice question :)