Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make sure DOM changes are finished before transition

Short version

When ui-router transitions to a new view (using ngAnimate in some way that I don't fully understand), it adds the classes ng-leave and ng-leave-active to the the current view. It also adds the classes ng-enter and ng-enter-activeto the next view. The problem is that the transition is started before all the DOM changes in the next view are finished, causing the transition to be choppy. So my question is; is it possible to prevent that the ng-enter and ng-enter-active classes are added until I decide that they should be added (by transmitting an event from a controller, or such)?

Long version

I am developing an AngularJS application which uses ui-router and ng-animate for transitions. I have run into a small performance problem, which I really would like to resolve to make the application run smoother.

The transitions between states seem to be stuttering, and I've found out that this is probably because during the transition Angular is performing DOM-changes while the transition is taking place.

How can I make sure that the DOM changes in the next view is finished before making the transition? I am using ui-router's resolve function together with promises that prevents the transition from taking place before the data is loaded.

I have created a JSFiddle that illustrates my problem. When clicking the link to enter state2, it takes a while for the resolve rows to resolve with data (just as expected). However, it doesn't seem like the DOM is ready when the transition takes place, since the transition can be quite laggy. This makes me think that the DOM is not ready when the transition takes place.

app.js

angular.module('myApp', ['ui.router', 'ngAnimate'])
.config(['$stateProvider',  
    function ($stateProvider) {
        $stateProvider
            .state('state1', {
                url: '',
                views: {
                    'main': {
                        templateUrl: "state1.html",
                        controller: function(){

                        }
                    }
                }
            })
            .state('state2', {
                url: '/state2',
                views: {
                    'main': {
                        templateUrl: "state2.html",
                        controller: function($scope, rows){
                            $scope.rows = rows;
                        },
                        resolve: {
                            rows: function($q){
                                var rows = [];
                                var deferred = $q.defer();

                                for (var i = 0; i < 10000; i++){
                                    rows.push({a: i, b: i/2, c: 3*i/2});
                                }

                                deferred.resolve(rows);

                                return deferred.promise;
                            }
                        }
                    }
                }
            });
    }])

templates

<div ui-view="main" class="main"></div>

<script type="text/ng-template" id="state1.html">
    <a ui-sref="state2">Go to state 2</a>
</script>

<script type="text/ng-template" id="state2.html">
    <a ui-sref="state1">Back to state 1</a>

    <table>
        <tr>
            <th>a</th>
            <th>b</th>
            <th>c</th>
        </tr>
        <tr ng-repeat="row in rows">
            <td>{{row.a}}</td>
            <td>{{row.b}}</td>
            <td>{{row.c}}</td>
        </tr>
    </table>
</script>

css

.main{
    transition: all 1s ease;
    position: absolute;
    width: 100%;
}

.main.ng-enter{
    transform: translateX(30%);
    opacity: 0;
}

.main.ng-enter.ng-enter-active{
    transform: translateX(0);
    opacity: 1;
}

.main.ng-leave{
    transform: translateX(0);
    opacity: 1;
}

.main.ng-leave.ng-leave-active{
    transform: translateX(-30%);
    opacity: 0;
}
like image 690
Anton Gildebrand Avatar asked Oct 31 '22 20:10

Anton Gildebrand


1 Answers

The issue is ng-repeat. It creates a watch for each element, so as the number of elements increase the performance degrades. More than 2000-3000 elements will definitely impact performance of ng-repeat.

If you really need to display large number of rows using ng-repeat, then I would suggest go for:
1. pagination
2. Infinite scroll using limitTo filter.

You can look here for reference:
https://stackoverflow.com/a/17350875/5052704

Hope this helps!!

like image 180
Vipul Agarwal Avatar answered Nov 15 '22 05:11

Vipul Agarwal