Skip to content
This repository has been archived by the owner on Oct 2, 2019. It is now read-only.

big array performance issue #389

Open
masscrx opened this issue Nov 10, 2014 · 77 comments
Open

big array performance issue #389

masscrx opened this issue Nov 10, 2014 · 77 comments

Comments

@masscrx
Copy link

masscrx commented Nov 10, 2014

Hi,
I have form for customer information, with three fields which use ui-select, every is for selecting country (country array length is 251) when countries array is loaded for ui-select it causes some lag on the page with this data, I've saw that there are some issues open with pagination for far future so now I can resolve my problem by adding checking for minimum input length for example 3 characters, than pagination is made on backend, but when customer is loaded with such information like $scope.customer.country_id I need to load all countries before, so solution with minium input length for 3 characters can't be applied in that case. Some ideas how to achieve that? I was trying to reduce watchers by adding :: to ui-select's expressions (one time binding - Angular 1.3 feauture) but with no result.

@amcdnl
Copy link
Contributor

amcdnl commented Nov 13, 2014

You could virtualize the list, only rendering DOM that are in view.

@masscrx
Copy link
Author

masscrx commented Nov 13, 2014

@amcdnl can you expand your idea? Now my script for counting watchers on the page is showing 3163 watchers (2 fields with ui-select and list of countries) so too too much.

UPDATE: I've reduced by 2000 watchers after remove datepicker from angular-ui packet.

@simkessy
Copy link

I could use an answer for this. I'm not sure how to proceed with a list of 14k in my dropdown. I wanted to use minLength but that's not implemented yet.

@masscrx
Copy link
Author

masscrx commented Nov 18, 2014

@simkessy I've implemented min length in my project, and limit with result, you can check related issue : #274 (comment) where I wrote solution for this. Here you can check how I resolved limit for result : https://gist.github.com/masscrx/3a9ba4b3df4cdd7012ea and in html you can add something like this then:

<ui-select-choices limit="10" refresh="checkCountry($select.search)"  refresh-delay="500" repeat="country as country in countries | filter: $select.search">

This is my workaround for big array till guys make some official functions for this ;-)

@amcdnl
Copy link
Contributor

amcdnl commented Nov 18, 2014

@masscrx sorry for the delay, busy week.

Virtualizing a list means only the viewable items are rendered in the dom. The other items may be in memory or paged at the server level when came into view.

Heres an example ( would not recommend trying with our select though ) but gives the idea: https://github.com/kamilkp/angular-vs-repeat

@amcdnl
Copy link
Contributor

amcdnl commented Nov 18, 2014

Tagging as an enhancement; PR's welcome if you want to contribute.

@dmccown1500
Copy link

this would be huge. I would not mind working on it at some point but that would require me to not be busy... so not any time soon I think

@maxisam
Copy link

maxisam commented Jan 27, 2015

+1

@amcdnl
Copy link
Contributor

amcdnl commented Jan 27, 2015

What about virtual dom like react type implementation?

@dmccown1500
Copy link

Interesting that might do the trick. With a react style dom we could have
the list already built and merely injected when the ui-select dropdown
opens.

On a related note I did notice we have a lot of slowdowns that just come
from "ng-if/show"s that are calling a function. I think those have to call
every cycle right?

@Anton-Rodionov
Copy link

I also noticed ng-if slows ui-select down when it gets opened, but after quick profiling I found that it's because of ngAnimate, that by default "animates" every ng-if, ng-show, etc. (a lot of requestAnimationFrame calls). When I turned-off ngAnimate for ui-select it became 2x faster.

But this is only if you use ngAnimate, of course.

@dmccown1500
Copy link

If this PR #430 could get merged in it would probably solve a lot of the issues as well by limiting the DOM size.

@seiyria
Copy link

seiyria commented Feb 25, 2015

Any word on virtualizing? This is something that's come up for us as well.

@dmccown1500
Copy link

I have not done anything with it. infinite scrolling may still be the best bet and if not that then #430

@paynecodes
Copy link

@Anton-Rodionov How did you turn off ngAnimate on the ui-select. I, too, am getting rAF calls for every item in the list, which slows it down considerably.

@dimirc dimirc added this to the 0.12.x milestone Mar 3, 2015
@dorrotman
Copy link

Also interested in turning off ngAnimate effect on the ui-select component, while keeping it working for other components.

@yaring
Copy link

yaring commented Mar 16, 2015

+1

@simison
Copy link

simison commented Mar 22, 2015

You guys might find some inspiration from here; select2/select2#781 — since Select2 guys were having similar problems.

@ahuang321
Copy link

+1

1 similar comment
@igorlino
Copy link

+1

@dmccown1500
Copy link

I have had recent success with infinite scroll using this library. http://binarymuse.github.io/ngInfiniteScroll/ it is a bit more work, but if you only have a few big lists then this is decent work around.

@simkessy
Copy link

@dmccown1500 could you post a demo of what you did?

@dmccown1500
Copy link

Hey sorry did not have a ton of time, but I threw together a plunker. It is not quite working right (no idea why seems like the same thing I did on our webapp) but should at least give you some direction: http://plnkr.co/edit/OwhFCyHz0mO1yZMj5UW5?p=preview

@dmccown1500
Copy link

Update ok I got it working now: http://plnkr.co/edit/OwhFCyHz0mO1yZMj5UW5?p=preview I realized we were using a modified version of the library. pretty small change but it was slightly different. All credit to the ng-infinite-scroll team for the bulk of the code

@tw-zz-rk
Copy link

@dmccown1500 thank you!! your plunker is very helpful :)

@dmccown1500
Copy link

@twrk glad to hear is was helpful. I love this library and would really like to see something like this get pulled in natively.

@dometec
Copy link
Contributor

dometec commented Apr 24, 2015

@dmccown1500 thank you too!! it's magic!

@brenovieira
Copy link

Yeah I saw it here, but I didn't see an option to disable tagging.

I have a list of airports and the user must select one of them, not create a new one.

Edit:
Actually contact-chips may do this:

extension chips

I'll take a look later today. That could work for me.
Thanks.

@facesea
Copy link

facesea commented Dec 17, 2015

i solved same problem, when i annotation a line code of select.js:
qq20151217-1 2x

@ssljivic
Copy link

+1

@simkessy
Copy link

Did anyone ever solve this? I have a list of 700 items and I'm getting complaints about performance with no clue how to go about solving this.

@simkessy
Copy link

@dmccown1500 is there a way to use virtual repeat from ngmaterial with ui-select to fix the performance issues

@dmccown1500
Copy link

@simkessy I never tried I moved to a different project where the library was not in use so it kind of fell off my radar. Seems like it might work?

@AdamGerthel
Copy link

I just moved from oi-select to ui-select because oi-select doesn't support using scope variables to populate its attributes for some reason. Took me a good 3-4 hours to re-theme from oi to ui and rewrite some code.

And now this... gah!

@simkessy
Copy link

@AdamGerthel, this isn't a fix exactly, but I was able to help my performance by introducing a min-length and using the refresh directives built in. Essentially, I would only populate the dropdown when the user entered at least 2-3 characters.

Pros: Significant performance improvement, instead of rendering 700 items I'm only showing a subset
Cons: You don't get a full list of values until you enter something

@AdamGerthel
Copy link

@simkessy thank you! It worked wonders. I followed this approach: #88 (comment)

@stringbeans
Copy link

@dmccown1500 thanks for providing your solution with infinite scroll! Very cool stuff :) Unfortunately it doesn't seem to be working with the latest version of ngInfiniteScroll as it attaches by default to the window and not the container. I tried using the exact copy of infinite-scroll you used in your plunkr demo and noticed that ui-select would redraw itself after increasing the limit dynamically, thus each time you scroll and it adds more items it skips back to the top of the list again.

were you able to get your solution to work with the latest versions of infinite scroll and ui-select (ie. 0.14.x or 0.16.0) ?

@dmccown1500
Copy link

@stringbeans I left the project where I was using ui-select so I have not kept that up to date. So if you need a feature from one of the newer versions then you are kind of out of luck. Sorry!

@wesleycho wesleycho removed this from the 0.12.x milestone Mar 27, 2016
@SunnyTam
Copy link

Is there any fix on this issue?

@user378230
Copy link
Contributor

@TravisTam feel free to submit any PRs you feel could improve performance.

I'll be happy to review 😃

@edriang
Copy link

edriang commented Jun 14, 2016

Hi, wanted to share what I did in my project..

First commented the same line that mentioned @facesea:
// .attr('ng-if', '$select.open'); //Prevent unnecessary watches when dropdown is closed

But also the major problem with ui-select is using it with array | filter syntax. As explained in this page https://toddmotto.com/use-controller-filters-to-prevent-digest-performance-issues/ using filter in html causes big performance issues because it gets called on every digest cycle.

Then, if you don't use filter in view, .attr('ng-if', '$select.open'); it's no longer necessary.

Finally I had to modify select.js to emit an "on-filter" event when $select.search changes, so I could update the source array when user types something.

$scope.$watch('$select.search', function(search){
        $scope.$emit('on-filter', search);
});

Hope this tips helps to improve the library.

@evenicoulddoit
Copy link

@stringbeans you're right, the latest infinite scroll plugin uses the window by default, but it does allow you to modify the container. The scope properties are:

{
  infiniteScroll: '&',
  infiniteScrollContainer: '=',
  infiniteScrollDistance: '=',
  infiniteScrollDisabled: '=',
  infiniteScrollUseDocumentBottom: '=',
  infiniteScrollListenForEvent: '@'
}

However... I've tried in vain to set it up to work correctly. You need to pass a selector to infiniteScrollContainer, and neither using .ui-select-choices-group nor #ui-select-choice-0 (which it looks like the old version was using automatically as the container) works.

@jocluz
Copy link

jocluz commented Aug 11, 2016

any news on this issue?

@user378230
Copy link
Contributor

@jocluz this issue is up to date with all info posted so far, what further news do you require?

Feel free to submit any PRs you feel could improve performance I'll be happy to review 😃

@benwigley
Copy link

benwigley commented Sep 28, 2016

I also have found a solution similar to some above, but in to my eyes was a bit more straight forward.

In the view

<ui-select-choices repeat="school in filterSchools($select.search)">
  <div ng-bind-html="school.name | highlight: $select.search"></div>
</ui-select-choices>

In the controller. I have a list of 3,000+ schools, and I have no need for the user to scroll through them all at once so I return an empty array when there is no search term. When there is a search term I limit the array to 30 items.

$scope.filterSchools = (search) ->
    return [] if !search
    limit = 30
    index = 0
    searchRegex = new RegExp(search, 'gi') # gi = global and case insensitive
    return $scope.schools.filter (school) ->
      if school.name.match(searchRegex) && index < limit
        index += 1
        return true

If you want the dropdown to look nice (invisible) when there are no items in the array then you might want to edit the css of . ui-select-dropdown and remove the border (I am using the selectize theme so this might vary depending on the theme).

@jacek213
Copy link

jacek213 commented Oct 3, 2016

@evenicoulddoit I'm also having a hard time integring ng-infinite-scroll. I've tried to add infinite scroll attributes to ui-select-choices like:

<ui-select-choices repeat="user.id as user in mmCtrl.users | filter: $select.search"
                   refresh="mmCtrl.onNextPage($select)"
                   refresh-delay="300"

                   infinite-scroll="mmCtrl.onNextPage($select, $event, true)"
                   infinite-scroll-distance='0'
                   infinite-scroll-container="#ui-select-choices-0"
                   infinite-scroll-parent="true"
                   infinite-scroll-use-document-bottom="false"
                   >

No success so far - probably because the container to which I'm pointing is not really a parent of ui-select-choices but it's the element to be scrolled itself.

@Remiz
Copy link

Remiz commented Nov 7, 2016

@benwigley I tried something similar to you, but in my case I have 100k records in a list... The dropdown gets populated really fast and it seems to work. I'm using a multiple select and when I select more than one object it transform all the objects to the one selected last... I think the binding can't work in my case but if I bind to the full list the performances are terrible. Not sure what to do.

@jacek213
Copy link

jacek213 commented Nov 7, 2016

@Remiz if you want to stick to ui-select, hooking up infinite scroll seems like the only option imho.

@7899
Copy link

7899 commented Nov 16, 2016

Infinite scroll solution is misleading. the problem still persists, if you keep scrolling down the performance will start to degrade again as the list grows and grows.

You can use LimitTo and Begin with dynamic variables that change when you hit ScrollTop and when you scroll to the bottom. But now I have a problem where the search only operates on what is in the list (restricted by the LimitTo) and not on the complete array. Is there a way to get it to search the underlying array instead? Any advice appreciated, I'm very close to having a solution to this problem!

@sshalayev
Copy link

IMHO, root of the problem is in intensive and undjustify use of forced digesting. Also I'd say that ngModel is used rather strange way. I didn't find a single $commitViewValue in the code.
Making long things short. After removing unnecessary calls to digest and doing small tweaks on how ngModel and $compile are used, I've got it working with suitable performance on large arrays. It's not ready for PR perhaps - I've tested only functionality I need. Hopefully someone can get good insights out of it

@user378230
Copy link
Contributor

@sshalayev it's a real shame you couldn't contribute your changes back to us here, I'm sure a lot of people would have been grateful if you did.

Consider submitting them in smaller chunks if you want, it will save you having to constantly keep your own fork up to date after all! 😁

@cristianocoelho
Copy link

Adding comments here since I'm also interested in a way to speed up performance, 200 rows already is a killer.

@gercheq
Copy link

gercheq commented Dec 10, 2016

@cristianocoelho @user378230 Checkout this one for a working version: #88 (comment)

@gscoppino
Copy link

We've also been having some performance issues with ui-select, specifically with lists of over 100 items. Disabling AngularJS driven animations by removing the ngAnimate module significantly improves perceived performance as noted by @Anton-Rodionov earlier. However, we only want to disable animations for ui-select and want other parts of our app to continue using AngularJS driven animations. A solution was found here in this issue description: #1502

In addition, there is a way to make the change on a per-instance basis and without forking the repository or keeping a locally modified copy of the library. We created a directive that requires uiSelect as a sibling and sets the instance of $animate to null, like so:

angular.module('my-module')
    .directive('uiSelectNoAnimate', () => ({
        restrict: 'A',
        require: 'uiSelect',
        link: (scope, element, attrs, $select) => {
            $select.$animate = null;
        }
    }));

and use as follows:

<ui-select ui-select-no-animate ...>...</ui-select>

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests