angular-ui / ui-select

AngularJS-native version of Select2 and Selectize
MIT License
3.26k stars 1.82k forks source link

Performance issues #88

Open filipedeschamps opened 10 years ago

filipedeschamps commented 10 years ago

Guys, we are suffering some serious performance issues. Does anyone know what is this $select.isActive(this) ?

Performance problem

dimirc commented 10 years ago

I can't find it, can you upload an example or point where on the src its used?

dimirc commented 10 years ago

Seams like this is related to https://github.com/angular-ui/ui-select/pull/49 code

DKirwan commented 9 years ago

Having the same issue. The batarang chrome developer tools extension (https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en) exposes this issue. Removing the code that highlights the list item that you're hovering over improves performance noticeably, but it is still very slow. Doesn't appear to be related to #49.

See line 903 in dist/select.js for more info.

$templateCache.put("selectize/choices.tpl.html","<div ng-show=\"$select.open\" class=\"ui-select-choices selectize-dropdown single\"><div class=\"ui-select-choices-content selectize-dropdown-content\"><div class=\"ui-select-choices-group optgroup\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label optgroup-header\">{{$group.name}}</div><div class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this)}\"><div class=\"option ui-select-choices-row-inner\" data-selectable=\"\"></div></div></div></div></div>");

askhogan commented 9 years ago

I saw the same thing in my app. I removed the isActive component and still have the same performance problem. It seems that if you load more than 10 ui select directives on the same page, the page becomes frozen for 5-6 seconds. I am using Mac OSX with the latest version of chrome.

I believe the performance issues are due to the ng-repeat mechanism in the ui-select-choices directive. I commented out this section of the code and the app became responsive again. It appears that the select dropdown list of choices is getting processed immediately, instead of when it is clicked on. If you have (several choices * several select-ui search boxes) on the same page it will slow down page load tremendously. I believe the solution is to delay the processing of the dropdown choices until a select-ui search box is clicked on, but I am still investigating...

The project I am using this with has one ui-select box per user. For large accounts with 50-150 users, loading can take about 15 - 30 seconds or cause chrome page to crash.

jurintalu commented 9 years ago

Any update on this? Same performance issues here aswell.

askhogan commented 9 years ago

This is not a permanent fix, but what I did was created a ng:if where I disabled the angular ui-select if the object was empty (e.g. no options selected). So for the directive to render a user must press on a button and then the UI renders. This prevents about 80% of the ui-selects from rendering on page for me and solved the problem.

My case is multi-select just to be clear.

Here is some sample code

<ui-select ng:if="user.hasExtensions"
///
</ui-select>   
                      <span ng:if="!user.hasExtensions"
                               ng:click="user.hasExtensions = true; refreshPlaceholder();"
                               class="btn-info-callinize"><i
                                     class='icon-plus-sign icon-white'></i></span>
jurintalu commented 9 years ago

Thanks but I have only one ui-select with roughly a thousand options. On IE9 it is pretty much unusable.

gjoliver commented 9 years ago

yeah guys, this is really bad. I have only 1 select with maybe 500 entries. And it's super slow. any idea where the problem may be?

gjoliver commented 9 years ago

ok I worked around this by doing repeat="...... | limitTo: 100", so we don't show a huge list of items.

oaprograms commented 9 years ago

@gjoliver limitTo solves the speed issue, but it would be even nicer if remaining items could be appended automatically when the list is scrolled to bottom.

rogerfar commented 9 years ago

Any update on this? This is kind of a dealbreaker for me. I am migrating from Kendo, and have a dropdown with over 5000 items. In Kendo it opens, loads and filters in ms, in ui-select it's sluggish and often freezes the browser.

aturkelson commented 9 years ago

I'm having the same issue with around 500 items. Sometimes the performance gets so bad that the browser actually crashes!

KevinPHughes commented 9 years ago

Also a problem for me. I can't do the limitTo: 'myNumber' trick because it doesn't allow previously selected items to be pre-populated unless they're within the first 'myNumber' of my source.

mareczek commented 9 years ago

Very recently (~ week ago) performance dropped even further. I have problems with a list of 103 items.

adamkidder commented 9 years ago

I recently switched from ui-select to angular-selectize due to performance. I'm dealing with lists of ~500 entries each and typing to filter is unacceptably slow.

buremba commented 9 years ago

@mareczek +1

vitto32 commented 9 years ago

what about "suspending" the watchers instead of using ngIf (which stresses DOM on long lists)? something like: https://coderwall.com/p/d_aisq/speeding-up-angularjs-s-digest-loop

igorlino commented 9 years ago

+1

pitieu commented 9 years ago

The performance issues are due to the ng-repeat mechanism in the ui-select-choices directive. Like askhogan said the dropdown list are getting processed immediately. Also i added a custom filter and whenever i hover over a dropdown list item, it calls filter for every item in the dropdown list and every time i hover over another item it renders the filter again for every single item in the dropdown list. (at 20 items it already starts to get slow)

vitto32 commented 9 years ago

The performance issues are due to angular design who makes you build slow apps e and slow components. It's a sad lesson I've learned using ui-select and trying to make it faster for my use case (country dropdowns). In my next project I'll probably look elsewhere (aurelia.io, react, etc..).

@pitieu the hover problem is maybe the easieast to fix in the "angular way". The ng-mouseenter (as any other angular directive or service) calls a full scope digest while a $select digest should be enough, as far as activeIndex is not intended to be used outside the dropdown scope. But that's just a little part of the problem. Both limitTo and infinite scrolling are possible workarounds but they come at a cost in terms of usability and more code to maintain and debug.

The way I solved my specific use case is a dirty hack. I've replaced the ng-repeat with a loop that rebuilds the entire dropdown content as a string. I don't know if this approach can be used by ui-select itself without breaking some piece of code (it probably would).

brondavies commented 9 years ago

Wow, this is a really old thread with no milestone set! Thanks for the vote of confidence. :confused:

igorlino commented 9 years ago

I think in general, github should enable voting per issue, to make transparent where most problems are or what users are most interested in. (of course the motivation/drive of every open source project is always different)

I can imagine many would be voting for this issue.

brondavies commented 9 years ago

@igorlino most people just use a :+1: comment to increase interest or resurrect old issues but I agree that this seems like more of a work-around than a feature. Just as well, you can "subscribe" to issues without directly making a comment and this demonstrates increased community interest in resolving issues.

oshai commented 9 years ago

I think this is related: https://github.com/angular-ui/ui-select/issues/389

jtheoof commented 9 years ago

:+1: I am also stunned by the slow performance, even on small arrays (< 300 items).

ZoharLiran commented 8 years ago

Seeing the same issue :+1:

dimirc commented 8 years ago

With https://github.com/angular-ui/ui-select/pull/1211 there should be some improvement

drewfreyling commented 8 years ago

@dimirc there is but not enough to close these issues.

pascalcarmoni commented 8 years ago

To activate the dropdown select choice only after x letter are typed :

<ui-select-choices refresh="CheckCity($select.search)" refresh-delay="400" Add filter

| limitTo: limitcitysearch"

Than you have : <ui-select-choices refresh="CheckCity($select.search)" refresh-delay="400" repeat="item.id as item in vm.territories | filter: {city: $select.search} | limitTo: limitcitysearch">

In controller

$scope.limitcitysearch = 5000; //Init with no limite : to see a previous selected valued in database (edit mode)

        vm.CheckCity = function (CityTyped) {
            if (CityTyped.length >= 1) {
                $scope.limitcitysearch = 100;
            }
            else {
              $scope.limitcitysearch = 0;
            }
        }
jasonbrandt42 commented 8 years ago

Is there an option to load only first 100 then load more as the user scrolls down?

lbolla commented 8 years ago

I am affected by this issue, too.

sgpalit commented 8 years ago

Anybody that will solve this problem?

igorlino commented 8 years ago

Sad to say, but after applying all hacks that I could, including the scrolling filter trick, it was simply not sufficient. So some radical change had to be done...

What did work, and is quite quite performant was to simply switch to another component https://github.com/machineboy2045/angular-selectize

The disadvantage is that is a wrapper to a jquery based component, and does not offer all the themes options.

The advantages are that the directive is very very small, the configuration of it is mostly not in the HTML but in the controller, so the HTML is much easier to read, configure and REUSE.

As the select does not know anything about angular, it also does not inherit Angular performance problems. selectize is very robust and has tons of options to adapt itself quite well to the angular lifecycle.

user378230 commented 8 years ago

@igorlino your update appears to be related to angular-selectize library not ui-select. It doesn't appear to help resolve any problems with performance or add meaningful information to what has already been drescribed.


Can I ask that future posters contribute meaningful updates to the issue.

Useful updates:

+1's are not helpful (please use github reactions), open issues are still outstanding and need to be addressed.

Again, PRs are more help than posting in issues.

Thanks all! :smiley_cat:

user378230 commented 8 years ago

Currently ctrl.items is searched everytime isActive is called which may be expensive if ctrl.items.length>1000.

ctrl.isActive = function(itemScope) {
    // ...
    var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]);
    var isActive =  itemIndex == ctrl.activeIndex;
    // ...
  };

It might be possible to improve isActive() by storing an activeItem rather than comparing on index every time.

Which would reduce isActive() to:

// Gets active item from active index somehow, needs to 
// account for changes to activeIndex and activeIndex value 
// when using tagging
var activeItem = getActiveItem();

ctrl.isActive = function(itemScope) {
    // ...
    var item = itemScope[ctrl.itemProperty];
    var isActive =  item == activeItem;
    // ...
  };
itchyny commented 8 years ago

The filtering logic of ui-select is heavy. The $scope.$apply and $timeout on the keydown event trigger $rootScope.$digest, which forces dirty check on the every watch expression (code: https://github.com/angular-ui/ui-select/blob/9d29307b7c3071e3a14bc15642a3775844d713c0/src/uiSelectController.js#L521-L574). I'm not sure it can be fixed to the local digest cycle. The ui-select2 library is wiser on filtering, it does not triggers the digest cycle on the root scope and faster on filtering, but deprecated 2 years ago.

yogeshgadge commented 8 years ago

I am going with a pagination support that works on scroll. It could be the raw list or the filtered list which may also be bad.

Plnkr Detailed solution on stackoverflow

mohamadnajiya commented 7 years ago

@yogeshgadge add clear to multiple ui-select will stop populating the dropdown

 $scope.clear = function($event) {
      vm.multipleDemo.selectedPeople=undefined;

  };

Plunk below

Plnkr

Any idea how to fix that?