0

So I have a simple ul that ng-repeats li elements from the external source gathered with a promise. I also have a search input that filters these elements, and I would like for the ul to hide when it contains no more elements that satisfy the search.

I made this directive, but its not working:

.directive('predictive', function() {
    return {
        restrict: 'A',
        link: function(scope, element) {
            console.log(element);
            if (!$(element).children("li").length) {
                $(element).hide();
            }
        }
    }
});

But the directive hides everything because it applies too fast, before the service that gets the data fills the list with li's.

Anything I can do about it?

EDIT: the markup

<input type="text" ng-model="predictiveSearch"></input>

<ul ng-repeat="(key, option) in Service1.predictive" predictive>
        <span><b>{{key}}</b></span>
        <li ng-repeat="option in option | filter:predictiveSearch">
          <a href="" ng-click="handlePredictiveSelection(option)">{{option}}</a>
        </li>
</ul>
CountGradsky
  • 268
  • 2
  • 4
  • 15
  • could you please add code used by "**I have a simple ul that ng-repeats li elements from the external source gathered with a promise**"? – Pankaj Parkar Jun 15 '16 at 09:39
  • there you go friend – CountGradsky Jun 15 '16 at 09:43
  • You are thinking about this all wrong. Those elements are generated from your data model. A simple `ng-if` that checks the data length would do what you need. Always think of the data model first, not the DOM. Also `` is not valid child of `
      `
    – charlietfl Jun 15 '16 at 09:47
  • noted! the thing is that the data will never be empty after it initially loads, it is just that the ul will be all filtered out of li's – CountGradsky Jun 15 '16 at 09:51
  • Use the filter alias of ng-repeat as the array to check length of in ng-if – charlietfl Jun 15 '16 at 10:01
  • @charlietfl is correct, `ng-if="option.length>0"` would do the trick instead of having directive – Pankaj Parkar Jun 15 '16 at 10:03

2 Answers2

3

You can use the filter alias of ng-repeat and check that length in an ng-if

<ul ng-repeat="(key, option) in Service1.predictive" ng-if="filteredArray.length">

        <li ng-repeat="option in option | filter:predictiveSearch as filteredArray">

        </li>
</ul>
charlietfl
  • 170,828
  • 13
  • 121
  • 150
1

You may try <ul ng-repeat="(key, option) in Service1.predictive" ng-hide="(option | filter:predictiveSearch).length == 0"> instead of creating a custom directive.

That would filter your options twice. If there are many of them, the better would be to do the filtering inside the custom directive so that it is performed only once and hide element with element.hide() instead of ng-hide.

.directive('predictive', function($filter) {
return {
    restrict: 'A',
    link: function(scope, element) {
        var filter = $filter('filter');

        scope.watch('predictiveSearch', function(value) {
            scope.innerOptions = filter(scope.option, value);
            if (!scope.innerOptions.length) {
                element.hide();
            }
        });

    }
}});

Now you should be able to iterate over innerOptions: ng-repeat="option in innerOptions" and the filtering is done once inside your directive.

  • Why would you need `element.hide()` and `ng-hide`? – charlietfl Jun 15 '16 at 10:15
  • You are right, it is not needed. These are two separate options: use `ng-hide` and filter twice, or filter once and hide element manually. In any case, the answer with using `as` syntax seems to be a better option. I just forgot that it exists. – Eugene Starov Jun 15 '16 at 10:22