6

I Have this code in my project. I try to add data from database using $http, but ng-repeat doesn't update de table, only shows a blank row.

When I check the scope, data is already there. I've read many answers but they does not seem to be related to my problem.

<div ng-controller="TweetsController">  
<table class="table table-striped table-bordered table-hover" width="100%">
    <thead>
        <tr>
            <th class="col-md-5"><i class="fa fa-fw fa-twitter text-muted hidden-md hidden-sm hidden-xs"></i> Texto</th>
            <th class="col-md-1 text-center"> Lista</th>
            <th class="col-md-1 text-center"> Cuenta</th>
            <th class="col-md-1 text-center"> Red</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="tuit in filtrado">
            <td>{{tuit.texto}}</td>
            <td class="text-center">{{tuit.lista.nombre}}</td>
            <td class="text-center">{{tuit.lista.cuenta.nombre}}</td>
            <td class="text-center">{{tuit.lista.cuenta.red.tipo}}</td>
        </tr>
    </tbody>            
</table>
<div>
    <pagination total-items="ufilter.length" itemsPerPage="itemsPerPage" ng-model="currentPage"></pagination>
</div>
</div>

Controller:

.controller('TweetsController', ['$scope','$http','filterFilter', function($scope,$http,filterFilter) {
    $scope.currentPage = 1;
    $scope.itemsPerPage = 10;
    $scope.filtrado = [];

    $scope.setPage = function (pageNo) {
        $scope.currentPage = pageNo;
    };

    // retrieve tweets
    $http.get('admin/twitter').success(function(tweets) {
        $scope.tweets = tweets;
    });

    $scope.saveTweet = function(isValid) {
        if(isValid) {
             var tuit = {
                texto: $scope.texto,
                lista_id: $scope.lista
            };

            $http.post('admin/twitter', tuit).success(function(t) {
                $scope.tweets.push(t);
            });
        }
    };

    $scope.filtrar = function(filtro) {
        if($scope.tweets != undefined) {
            $scope.ufilter = filterFilter(filtro, $scope.buscar);

            var inicio = ($scope.currentPage - 1) * $scope.itemsPerPage;
            var fin = inicio + $scope.itemsPerPage;

            $scope.filtrado = $scope.ufilter.slice(inicio, fin);
        }
    };

    $scope.$watch('tweets', function() {
        $scope.filtrar($scope.tweets);
    });

    $scope.$watch('currentPage', function() {
        $scope.filtrar($scope.tweets);
    });

    $scope.$watch('buscar', function() {
        $scope.filtrar($scope.tweets);
        $scope.setPage(1);
    });     

}])

EDIT:

I Solved it!

The problem is the way how the retrieve data is wrapped

$scope.tweets.push(t[0])
1
  • Please don't forget to create an answer, and tag it. So people won't spend time answering an open question. :) Commented Aug 28, 2014 at 22:14

4 Answers 4

10

You need to apply to the scope

 $http.get('admin/twitter').success(function(tweets) {
        $scope.tweets = tweets;
        $scope.$apply()
});

This is a great blog post that explains it:

http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

The reason why your ng-repeat is not updating after the $http request is due to the $http is async and your javascript turn for the controller has finished before the response is back from your $http request. So you must notify the scope that things have changed and push it to the scope.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the answer. When I put that, browser throws an error: $digest already in progress :(
I think the problem is scope.watch , should be scope.watchCollection, as collection changes, not tweets reference. You do not have to call scope.$apply.
I tried with scope.watchCollection but it does the same thing
Real hero. Saved hours of frustration. Thank you mate.
3

The problem is the way how the retrieve data is wrapped

instead of this:

$http.post('admin/twitter', tuit).success(function(t) {
            $scope.tweets.push(t);
        });

this:

$http.post('admin/twitter', tuit).success(function(t) {
            $scope.tweets.push(t[0]);
        });

Comments

0

There is the easy way and the correct way.

This is the easy way

//Utility Functions
function Digest($scope) {
    //this may not be future proof, if it isn't then you may have to try $timeout(function(){//do something})
    if (!$scope.$$phase) {
        try {
            //using digest over apply, because apply fires at root, and I generally don't need root.
            $scope.$digest();
        }
        catch (e) { }
    }
    //console.log('$scope snapshot:', $scope);
}

In your code use this by calling

        $http.post('admin/twitter', tuit).success(function(t) {
           Digest($scope.tweets.push(t));
        });

This is the correct way.

https://docs.angularjs.org/api/ng/service/$q

Have your HTTP call wrapped in a $q promise. Then when it is either succeed or error, then fulfill the promise. The repeater will honor the promise.

Comments

0

For anyone else who may run into this issue where the UI just isn't updating - even after doing an $apply or sticking within a $timeout. I've just realised I made a stupid mistake and had added :: to the embedded property and forgotten about it.

So I had my ng-repeat and inside I had a {{ ::item.name }}. For those of you who don't know what the :: does; it tells angular to set the data and not set any additional watches, which in turn then stops angular trying to update that property. This is useful for data that you know won't ever change. See the below link for more information on one time bindings: http://blog.thoughtram.io/angularjs/2014/10/14/exploring-angular-1.3-one-time-bindings.html

So my solution was just to remove the :: so: {{ ::item.name }} became {{ item.name }}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.