UPDATE1: Started using ngProgress, but not giving required effect in IE.
Final Update: Best solution found. See last answer below.
The AngularJS application has multiple tabs and each tab may have up to 100 fields. The Data is retrieved from DB using several Ajax calls and a related loop is used to initialize each of the following: validation rules, drop-down list items and finally the field values. In some cases, we are using combination of Javascript and AngularJS way to get the required effect.
Mind you that loading of Validation Rules involves modifying the directive such as ng-required
and ng-max
which will require to use $compile
to activate the validation rule.
This question has two parts:
- AngularJS App has noticeable slow loading effect under IE. Under Chrome Browser, loading speed is much better.
How we can troubleshoot and analyse slow loading issues under IE to pinpoint the location of the issue? How I can work on performance analysis tools under IE?
- In the meantime, thinking to add Progress Bar to be updated after completing loading each of the data parts mentioned above: Validation Rules, drop-down list items, and field values.
I implemented ngProgress plugin in my project, and it works fine under Chrome, but under IE it is not giving the required effect. The progress bar will show and complete at the very end of page loading. It seems under IE that the progress bar won't show immediately at the start of the page rendering. Mind you that in my project I am using directive extensively, and large number of them use $compile
service.
I did some research, and realized that IE won't update the DOM display immediately... it will wait until a later stage to update all at once, or at least this was my understanding. So the trick here is how to force the IE to reflect DOM changes as soon as possible.
I used this approach which helped get better results under IE:
app.controller('formMainController', ['$scope', '$timeout', '$interval', 'ngProgressFactory',
function($scope, $timeout, $interval, $q, ngDialog, ngProgressFactory) {
$scope.progressbar = ngProgressFactory.createInstance();
$scope.progressbar.start();
$scope.stopProgressbar = $interval(function(){
$scope.progressbar.setParent(document.getElementsByTagName("BODY")[0]);
},10);
...
...
//After getting all data from DB
$scope.mainPromise.then(function(success) {
$interval.cancel($scope.stopProgressbar);
$timeout(function(){
$scope.progressbar.complete();
}, 3000);
return 'main promise done';
})
}]);
With the above, under IE, I can see the progress bar showing much earlier than before, then it will make 2 step progress, then it will freeze for about 2 seconds, then continues normally. When watch the console window, I can see that it will freeze while the other many directives are being executed especially the one that uses $compile
service with priority: 100
and terminal: true,
.
Any idea how to make it better?
Note: This thread has similar problem, but I didn't find a relevant solution.
Tarek
The problem got worse after reaching 1000+ fields. IE 11 took 3+ minutes to complete loading. I did further optimization and now the results are as follows for the time to complete loading:
It is confirmed that the bottleneck is in the loop that will load the validation rules and apply them on the elements, then it will perform compile using
$compile
service.The validation rules are stored in DB using json format and retrieved using
requiredFieldsPromise
. See code sample below.Following is the new updated code for directive
check-if-required
:Though the performance now is much better now, however, I realized that the problem is in using
$compile
, therefore, I am now thinking to find a solution by avoiding use of$compile
. Here is my plan.Instead of modifying the element HTML by adding 'ng-required' directive, then compile, instead, I can skip HTML and use the
ngModel.NgModelController
of the related HTML Element, then access the$validators
to perform validation using code. If you read the code above, you will see that I have already accessed thengModel.NgModelController
for each element in variableelmModel
. I think this variable will provide access to$validators
which can be used to add validation to the element. Since the rules are now available invalidationList
variable, I will write a function to perform validation by looking up this list and apply the available validation on-the-fly.This will be the improvement in the future sprints.
If you have any feedback, please let me know.
Tarek
This is the final version, and the best in terms of performance.
It is based on the following:
ngModelController.$validators
property.directive
and$compile
completelyFollowing is the code that will be used to load the validation rules:
And the code below can be used to load and trigger validation:
and, to load the
readonly
rules, you need to run this code when done rendering all elements:And you can use the directive
when-rendering-done
as defined in this solutions:From what you have said the slow loading is due to AngularJS working as opposed to data loading [as evidenced by the fact its slower in IE than Chrome]. If this is true then a loading indicator wont help as it'll just freeze too.
You are far better off following normal performance techniques in angular such as:
{{::vm.name}}
<div ng-bind="::vm.name"></div>
rather than handle bars{{::vm.name}}
Here is my solution based on solution by @andrew above and using ngProgress Bar component.
CSS:
JS - in the beginning:
JS - in the end:
Finally, I was able to achieve the best acceptable performance for Chrome and IE.
Following are the main changes that fixed the problem in the previous code:
//delete validationList[childID]
required='required'
instead ofng-required='true'
.Following is the updated code for directive
check-if-required
:Following are the performance results for loading 1000+ fields and validation rules: