Reputation: 3279
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!
Upvotes: 3
Views: 11953
Reputation: 93
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"
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!
Upvotes: 3
Reputation: 513
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
.
Upvotes: 2
Reputation: 6982
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.
Upvotes: 8