2

I'm using angular 1.4.8. I want to save filtered result from ng-repeat and use it to determine whether to enable a "load more" button at the bottom of the list. I have looked at this question:

AngularJS - how to get an ngRepeat filtered result reference

And many others, they suggest to use "as alias" from ng-repeat, here's what my code looks like:

  <ul class="media-list tab-pane fade in active">
    <li class="media">
      <div ng-repeat-start="item in items | limitTo: totalDisplayed as filteredResult">
        {{item}}
      </div>
      <div class="panel panel-default" ng-repeat-end>
      </div>
      <div>
        {{filteredResult.length}}
      </div>
    </li>
  </ul>
  <button ng-click="loadMore()" ng-show="totalDisplayed <= filteredResult.length">
    more
  </button>

However, I found filteredResult.length is displayed fine right after ng-repeat, but the button is never shown. If I try to display filteredResult.length in where the button is, it will show null.

So is there a rule for "as alias" scope? I've seen plenty of examples work but mine doesn't, what am I missing here?

EDIT:

The accepted answer uses controllerAs which indeed will resolve the problem. However, charlietfl's comment using ng-init to save filteredResult to parent scope is also very neat and that's the solution I use in my code eventually.

Community
  • 1
  • 1
swang
  • 5,157
  • 5
  • 33
  • 55
  • 1
    Could you post a plunkr reproducing the problem? Is any of the `media-list tab-pane fade in active media` classes a selector for a directive that would have its own scope? – JB Nizet Mar 06 '16 at 15:25
  • 1
    Works fine here http://plnkr.co/edit/oSQP4KqezESBporw28vX?p=preview I suspect you have some other scope issue not shown in code above – charlietfl Mar 06 '16 at 15:34
  • Should work, do you try log totalDisplayed value? – Slava N. Mar 06 '16 at 15:56
  • @charlietfl: you are right, I think it has something to do with ng-if, in my actual code I have a ng-if="showSomething" in the ul(not the button) , but I don't understand why, see this example based on yours:http://plnkr.co/edit/qFUybIHFQrHVvIh76UFv?p=preview why the more button disappeared? – swang Mar 06 '16 at 16:54
  • 1
    @swang because ng-if defines its own scope (it behaves as if you had `ng-controller="SomeOtherController"` on the ul). So filteredResult is set on the ngIf scope, and not on your controller scope. Since the button is out of the ng-if scope, it can't access filteredResult. – JB Nizet Mar 06 '16 at 16:58
  • `ng-if` creates a child scope that's one reason `controllerAs` is popular but also setting models as objects on scope helps...insted of direct properties of scope for each variable – charlietfl Mar 06 '16 at 16:59
  • @charlietfl, can you please explain how to "setting models as objects on scope helps...insted of direct properties of scope for each variable", controllerAs is a good solution but it would require code change to every access of scope property, if there's a way to resolve this just when using ng-if i would prefer that. – swang Mar 06 '16 at 19:13
  • what if you switch to `ng-show`? It doesn't create child scope. – charlietfl Mar 06 '16 at 19:35
  • @charlietfl that was my original solution, but I read about ng-if can improve the performance because DOM elements are not created at all. In my case i have 1000+ items, depends on the ng-if condition, only one half of them will be shown. – swang Mar 06 '16 at 19:38
  • 1
    Here's a possibility using an object on scope and `ng-init` http://plnkr.co/edit/i0GKXAVTRjHWnelQpoAs?p=preview – charlietfl Mar 06 '16 at 19:47

1 Answers1

1

Probably some of classes in your <ul class="media-list tab-pane fade in active"> or <li class="media"> is selector for a directive that would have its own scope. So you store filteredResult in e.g. tab-pane's scope and then try to have access out of it's scope in outside of ul tag.

Try to use Controller as instead of scope:

angular
  .module('plunker', [])
  .controller('MainCtrl', function() {
    vm = this;
    // make an array from 1 to 10
    var arr = [];
    while (arr.length < 10) {
      arr.push(arr.length + 1)
    };

    vm.items = arr;
    vm.totalDisplayed = 5;
    vm.filteredResult = [];
  });

<body ng-controller="MainCtrl as main">
  {{main.items}}
  <ul class="media-list tab-pane fade in active">
    <li class="media">
      <div ng-repeat-start="item in main.items | limitTo: main.totalDisplayed as filteredResult">
        {{item}}
      </div>
      <div class="panel panel-default" ng-repeat-end>
      </div>
      <div>
        filteredResult = {{main.filteredResult = filteredResult}}
      </div>
    </li>
  </ul>
  <button ng-click="loadMore()" ng-show="main.totalDisplayed <= main.filteredResult.length">
    more
  </button>
</body>


http://plnkr.co/edit/drA1gQ1qj0U9VCN4IIPP?p=preview
doroshko
  • 746
  • 5
  • 16
  • what if i'm using ui-router and set Controller in the router rather than html? if i put ng-controller in I would load my controller twice. – swang Mar 06 '16 at 16:56
  • @swang You can use controller as in ui-router: `controllerAs: 'main'` – doroshko Mar 06 '16 at 17:08