Angular.js: Angular is loading items twice for a short period

Created on 14 Apr 2017  路  8Comments  路  Source: angular/angular.js

I'm submitting a ... - [x] bug report

Current behavior: Angular is loading items twice for a short period

Angular version: 1.6.1

Browser: [all]

enter image description here

This issue has also been posted here.

Angular is loading items twice for a short period

The only time it loads the right items is on first page load. Then, on every refresh it loads the items twice for half of second, like you see in the GIF.

My code is dead simple, it feels wrong to post it, but i will. I tried ng-cloak on table, but nothing is changed. Any ideas why it's doing this and how can i make it stop?

    var RefreshData = function () {
        Machine.getAllMachines().then(function (response) {
            machineList.allMachines = response.data
            console.log('RefreshData 6 sec', machineList.allMachines)
        })
        setTimeout(RefreshData, 6000)
    }
    RefreshData()


<table class="table table-striped table-hover table-bordered">
    <thead>
        <tr>
            <th>Ip</th>
            <th>Status</th>
            <th>Department</th>
            <th> Processor</th>
            <th>Action</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="item in machineList.allMachines">
            <td>{{item.Ip}}</td>
            <td>ONLINE</td>
            <td>{{item.Department}}</td>
            <td>{{item.Processor}}</td>
            <td>Edit</td>
        </tr>
    </tbody>
</table>

Update:
Recreated the loop with button click and it's the same effect. So the timeout is not the problem.

enter image description here

Most helpful comment

What is going on?

Every time you refresh the data, you create new machine items (even if they look identical to previous ones, they are new instances). ngRepeat (which by default tracks items by identity), will identify them as new items, so it will add new rows for the new items and remove the rows for the old items.

Since ngRepeat is animation-aware, it removes and adds items via $animate, which allows you to easily provide animations for the ng-enter/ng-leave events. Adding the table-hover class, gives the table rows a transition style, which makes $animate believe there is an animation to be performed. Thus, the removed rows stay in the DOM for the duration of the animation (0.2.s). For these 0.2s, you have the old and new rows both present in the DOM.

How to solve it?

Off the top of my head, there are two possible solutions (in order of preference - but it really depends on your usecase):

  1. If the returned machines have a unique identifier (e.g. their IP), you can let ngRepeat track them by that (instead of tracking them by identity). E.g.:

    <tr ng-repeat="item in (machineList.allMachines | ...) track by item.Ip ">
    
  2. If you don't want to have animations on removed rows, you can specify a style (with a higher specificity than bootstrap's .table-hover > tbody > tr) that removed the transition. E.g.:

    table > tbody > tr.ng-animate {
      transition: none;
    }
    

All 8 comments

This doesn't look like an actual bug, however, to be sure could you provide a reproduction sample using something such as plunkr ?

I tried reproducing this in a simple plunkr but it works as expected. Maybe you're having something that makes your digest loop take some time ?
Here's my plunkr: https://plnkr.co/edit/aXciHkslKatBBdzlTJqT?p=preview

This sounds like a general support question. Please, use one of the appropriate support channels for these types of questions.
GitHub issues are reserved for bug reports and feature requests.

Thx!

I tried to recreate the glitch in many ways from scratch, but failed. So i decided to rip my app to pieces until it will stop doing it.
So after stripping it to the bone i started cutting css classes, and it turned out that table-hover it was doing this lol xD!

I tried to recreate it in plunker but failed again.
If you want to see the bug in action you have to download my app at this stage npm install, node server, and just add table-hover to MachineList.html.

Thanks for your help!

I cannot reproduce the problem, because I get some mongo related error. Happy to investigate if you can provide a way to reproduce this.

You just have to have MongoDB started in a terminal or a service.

@muscaiu Generally it's easier for anyone to investigate it if there's no need for those 3th party stuff.
E.g: requiring MongoDB makes me unable to run the app on the PC I'm currently using.

Any possibility to remove mongodb as a dependency ?

Often a 3th party plugin can also be the reason for the issue you're facing. However, in this particular case I doubt it's being caused by MongoDB :D

No dependencies project
I have removed all server, db, dependencies and node_nodules. You can now start it with 'http-server' or 'live-server' (at least that's what i use) or any local web server.
I managed to preserve the glitch.

What is going on?

Every time you refresh the data, you create new machine items (even if they look identical to previous ones, they are new instances). ngRepeat (which by default tracks items by identity), will identify them as new items, so it will add new rows for the new items and remove the rows for the old items.

Since ngRepeat is animation-aware, it removes and adds items via $animate, which allows you to easily provide animations for the ng-enter/ng-leave events. Adding the table-hover class, gives the table rows a transition style, which makes $animate believe there is an animation to be performed. Thus, the removed rows stay in the DOM for the duration of the animation (0.2.s). For these 0.2s, you have the old and new rows both present in the DOM.

How to solve it?

Off the top of my head, there are two possible solutions (in order of preference - but it really depends on your usecase):

  1. If the returned machines have a unique identifier (e.g. their IP), you can let ngRepeat track them by that (instead of tracking them by identity). E.g.:

    <tr ng-repeat="item in (machineList.allMachines | ...) track by item.Ip ">
    
  2. If you don't want to have animations on removed rows, you can specify a style (with a higher specificity than bootstrap's .table-hover > tbody > tr) that removed the transition. E.g.:

    table > tbody > tr.ng-animate {
      transition: none;
    }
    
Was this page helpful?
0 / 5 - 0 ratings