Slow performance with angular material md-select and ng-repeat
Solution 1
Angular material has very poor performance, because the objects pinned to the scope are huge, which makes the digest cycle very long and inperformant.
You should try it first with the default select
and ng-options
(DOCS HERE). If this works better for you, I'd suggest using plain html and then use MaterializeCSS to get the look and feel of Material Design.
Solution 2
Yes, making it all plain old html will speed it up, however then you lose all the eye candy. To have the good parts from both of the worlds you can do some basic optimizations.
-
Do you really need to watch the collection - are the collections going to change and if so can't you trigger a digest then? As you did with the id you can also one-way bind the repeated collection as well.
ng-repeat="id in ::serviceReferences"
- You don't really need all the options preloaded, right? Since you're using angular-material, the default drop-down will be exchanged with multiple elements, to emulate the drop-down behavior. I did just remove the options list, replaced it with the actually selected element and populate the list only when the control has gained focus. See documentation.
Still I agree the angular-material has a poor performance. It simply does not scale well. 1-2 controls work but if you have more then 10 it starts to fail.
PS.: Don't cook the $scope soup!
Solution 3
For a big amount of items in ng-repeat
will cause some issues. When angular use ng-repeat
to create nested list , a single watcher will be created for each item. Hundreds of watchers will slow down the performance obviously on moible (and IE probably). We used have this issue with ng-repeat
, so the best practice is avoid using ng-repeat
if you could, create and attach the watcher
when you really need to.
So I think the possible solution is, try to use normal for loop instead of ng-repeat
.
tkarls
Updated on June 07, 2022Comments
-
tkarls almost 2 years
I'm writing an enterprise application using angular and angular material and have problem with the performance of a medium sized (in my opinion) form. Especially in IE.
(Working demo, see https://codepen.io/tkarls/pen/vGrqWv . Klick on the card title and it pauses slightly before opens. Especially using IE and mobile. Desktop chrome works pretty well.)
The worst offenders in the form seem to be some md-selects with ng-repeat on them.
<md-select ng-model="form.subchannelId" ng-disabled="vm.readOnly"> <md-option ng-repeat="id in subchannelIds" value="{{::id}}">{{::id}}</md-option> </md-select> <md-select ng-model="form.serviceReference" ng-disabled="vm.readOnly"> <md-option ng-repeat="id in serviceReferences" value="{{::id}}">{{::countryId}}{{::id}}</md-option> </md-select> <md-select ng-model="form.audioCodec" ng-disabled="vm.readOnly"> <md-option ng-repeat="audioCodec in audioCodecs | orderBy:'toString()'" value="{{audioCodec}}">{{::systemVariables.encoders.aac[audioCodec].displayName}}</md-option> </md-select> <md-select ng-model="form.audioSource" ng-disabled="vm.readOnly"> <md-option ng-repeat="audioSource in audioSources | orderBy:'toString()'" value="{{audioSource}}">{{audioSource}}</md-option> </md-select> <md-select ng-model="form.padSource" ng-disabled="vm.readOnly"> <md-option ng-repeat="padSource in padSources | orderBy:'toString()'" value="{{::padSource}}">{{::padSource}}</md-option> </md-select> <md-select ng-model="form.lang" ng-disabled="!form.generateStaticPty || vm.readOnly"> <md-option ng-repeat="langKey in langKeys | orderBy:'toString()'" value="{{::langs[langKey]}}">{{::langKey}}</md-option> </md-select> <md-select ng-model="form.pty" ng-disabled="!form.generateStaticPty || vm.readOnly"> <md-option ng-repeat="ptyKey in ptyKeys | orderBy:'toString()'" value="{{::ptys[ptyKey]}}">{{::ptyKey}}</md-option> </md-select>
The data model looks like:
$scope.subchannelIds = [0, 1, 2]; //up to 63 in real life $scope.serviceReferences = ["000", "001", "002"]; //up to 999 in real life $scope.ptys = { "No programme type": 0, "News": 1, "Current Affairs": 2}; //Up to ~30 in real life $scope.ptyKeys = Object.keys($scope.ptys); $scope.langs = { "Unknown": "00", "Albanian": "01", "Breton": "02"}; //Up to ~100 in real life $scope.langKeys = Object.keys($scope.langs);
The other ng-repeats are small with 3-5 items each. I think that a modern browser should handle datasets of this size and render it very quickly. So hopefully I'm doing something wildly wrong with my HTML code. The data is fetched from the server in real life but I do pre-fetch it so once the form is ready to be displayed it is already in the $scope.
I tried to pre-generate HTML after I fetched the data using normal js loops. And then insert just the html snippet like: {{::preGeneratedHtmlHere}}
But then angular would not treat it as html but text...
Any help on how to optimize this is appreciated!
-
tkarls about 8 yearsRight, I did try to reduce the number of watcher by using the {{::id}} syntax. But it does not seem to matter for the inital load time. If doing normal loop. How do I attach the html. ng-bind-html as @Murwa suggests?
-
tkarls about 8 yearsI see, I'll try and convert it to plain html selects and see what happens with the performance
-
David Tao about 8 yearsYeah, I saw you use
::id
which is one-way binding. If you want to get rid of the watchers you need to write the directive yourself and that means a lots of coding. -
tkarls about 8 yearsI tested it now without any css styling. And in chrome the form is now blazingly fast. And IE is improved but still not good enough.
-
tkarls about 8 yearsI'm selecting this as the accepted answer since doing it greatly improved the performance. However, to get the final user experience good enough I also combined ng-if and ng-show. So that ng-if = true on moseover and then ng-show = true on click. That created very rapid forms in both explorer and chrome!
-
tkarls about 8 yearsI've explained my technique here: stackoverflow.com/a/36795321/1226268 for anyone finding this on google.
-
rainabba about 7 yearsThis made just enough difference that the timing is acceptable for me. I didn't have a large number of items and actually thought the animation timing might just have been too slow, but this JUST brought the performance to an acceptable point and works since my lists won't be updating.
-
p0stm almost 7 yearsActually the objects are not necessary huge, it depends on what you define. Also the digest cycle is all about updates, while the original question complains about initial (compile + link) performance. As I wrote in my answer stackoverflow.com/questions/36764414/… this is because md-select, compiles all options. This can be deferred until the dropdown has been clicked. Fine-tune it by getting the list on focus maybe.