ng-repeat continuously fired on hover
Asked Answered
H

1

6

I'm using UI-Select 0.8.4 and have a large data set. Then I'm using UI-Select to display property values in a dropdown beside the data set. I'm using that for filters. So when choosing from the dropdown, will filter the results.

Every time when I hover over some item in the dropdown, it always fires the ng-repeat filter.

This is lagging my application because I'm working with a large set in the ng-repeat.

Why is this?

GIF: https://i.sstatic.net/fPBEz.gif

Plunker (open console and see for yourself): http://plnkr.co/edit/OxiutZ8t4IX1bOxiOTgo?p=preview

HTML:

<h3>Age list</h3>
  <p>Selected: {{age.selected}}</p>
  <ui-select ng-model="age.selected" ng-disabled="disabled" style="width: 300px;">
    <ui-select-match placeholder="Select a person">{{$select.selected}}</ui-select-match>
    <ui-select-choices repeat="age in ageArray | filter: $select.search">
      <div ng-bind="age | highlight: $select.search"></div>
    </ui-select-choices>
  </ui-select>

JavaScript:

$scope.theFilter = function(item) {
    console.log(item);
    return item;
  };

  $scope.ageArray = [];
  $scope.$watch('people', function(item) {
    for(var i = 0; i < item.length; i++) {
      $scope.ageArray.push(item[i].age);
    }
  });

  $scope.people = [
    { name: 'Adam',      email: '[email protected]',      age: 10 },
    { name: 'Amalie',    email: '[email protected]',    age: 12 },
    { name: 'Wladimir',  email: '[email protected]',  age: 30 },
    { name: 'Samantha',  email: '[email protected]',  age: 31 },
    { name: 'Estefanía', email: 'estefaní[email protected]', age: 16 },
    { name: 'Natasha',   email: '[email protected]',   age: 54 },
    { name: 'Nicole',    email: '[email protected]',    age: 43 },
    { name: 'Adrian',    email: '[email protected]',    age: 21 }
  ];

Edit: I even tried to filter the property values out of the "data set array" and using that in the dropdown, but it doesn't work.

Edit 2: If you think that the watch was triggering this, I removed the watch and this is still a problem: http://plnkr.co/edit/oD3Tt3vfjtOjADMnemW1?p=preview

Edit 3: Still haven't found a solution for this so I'm stuck with chosen. I created an issue but haven't gotten any response. Please upvote the issue if you want this fixed.

Hyaloid answered 1/12, 2014 at 18:1 Comment(0)
I
3

The issue is that the filter is executing on every $digest (every ng-mouseenter, ng-click, etc). For a huge data set, this can obviously kill performance. (See this article http://www.bennadel.com/blog/2489-how-often-do-filters-execute-in-angularjs.htm)

Instead, try a $watch on the age.selected value, then applying a filter only when that value actually changes.

http://plnkr.co/edit/TIeKPAyrAQsGHwakqwEp?p=preview

HTML

<!-- filtered list "ageMatches" -->
<ul ng-show="age.selected">
  <li ng-repeat="person in ageMatches">{{person.name}} - {{person.age}}</li>
</ul>

<!-- default list of all "people" -->
<ul ng-hide="age.selected">
  <li ng-repeat="person in people">{{person.name}} - {{person.age}}</li>
</ul>

JS

// add age to scope
$scope.age = {};

// add age match placeholder  
$scope.ageMatches = [];

// watch age.selected for changes, apply filter
$scope.$watch('age.selected', function(newVal, oldVal){
  if(newVal){
    $scope.ageMatches = $filter('filter')($scope.people, {age: newVal});
  }
});
Illiquid answered 3/12, 2014 at 16:32 Comment(4)
Thank you, but this filter I'm using is very complex and consists of many ng-models under $scope.filters.* - I think it's bloat to add a watch for each one, instead of having it in the ng-repeat. The question is however, is the ng-mouseenter necessary? Does it need to fire on hover, not just click? I personally think this is a flaw in the library.Hyaloid
Agreed, worst part is, I think the only purpose of the mouseenter is to apply an "active" class... too bad this ends up killing performance #csspleaseIlliquid
Might suggest removing the ng-mouseenter from the templating in the lib code.Illiquid
What did you do finally?Lancers

© 2022 - 2024 — McMap. All rights reserved.