André Luiz
André Luiz

Reputation: 7292

AngularJS: weird behavior with the 2-way binding (ng-repeat)

I'm using AngularJS in a Firebase app and I have a function where I do some inner join to get some data. More details here. After getting the response from the firebase api I create an object and push it into an array (a scope variable). I see in the debug that the data has been retrieved and that the $scope variable is filled correctly. The problem is that it is not showing in the ng-repeat.

My function:

$scope.getMessagesByRegion = function(regionId){

    console.log('Function start');
    var rootRef = firebase.database().ref();
    var regionMessagesRef = rootRef.child("region_messages/"+ regionId);
    $scope.messages_by_region = []; // Here I reset the scope variable

    regionMessagesRef.on('child_added', function(rmSnap) {

        var messageRef = rootRef.child("messages/"+rmSnap.key);
        messageRef.once('value').then(function(msgSnap){

            var msg = {
                key : msgSnap.key,
                name : msgSnap.val().name,
                type : $scope.getTypeName(msgSnap.val().type),
                show_only_once : rmSnap.val().show_only_once,
                pre_requisite_message : rmSnap.val().pre_requisite_message
            }
            console.log(msg); // here I see the object in the console. it is OK
            $scope.messages_by_region.push(msg); // pushing the item
            console.log('----------------');
            console.log($scope.messages_by_region);
        })

    });
}

My HTML:

            <table class="table">
                <thead>
                <tr>
                    <th>Message name</th>
                    <th>Type</th>
                    <th>Show only once</th>
                    <th>Pre requisite</th>
                </tr>
                </thead>
                <tbody>
                <tr ng-repeat="msg in messages_by_region">
                    <td ng-bind="msg.name"></td>
                    <td ng-bind="msg.type"></td>
                    <td ng-bind="msg.show_only_once"></td>
                    <td ng-bind="msg.pre_requisite_message"></td>
                </tr>
                </tbody>
            </table>

This is what I see in the console:

enter image description here

The problem is that even having an object in the array it is not shown in the view. It is like there was an empty array set to the $scope.messages_by_region variable

I'm having a hard time figuring out what I'm doing wrong. Can you see what's wrong with my function?

Thanks for any help.

Upvotes: 2

Views: 66

Answers (3)

Azad
Azad

Reputation: 5264

try,

$scope.$apply(function(){
 $scope.messages_by_region.push(msg);
});

or,

$scope.messages_by_region.push(msg);
$scope.$apply();

Upvotes: 2

Seeker
Seeker

Reputation: 1897

As you are performing Async calls you need to tell angular to refresh the changes in the value with $apply call you can do it with:

$scope.getMessagesByRegion = function(regionId) {

  console.log('Function start');
  var rootRef = firebase.database().ref();
  var regionMessagesRef = rootRef.child("region_messages/" + regionId);
  $scope.messages_by_region = []; // Here I reset the scope variable

  regionMessagesRef.on('child_added', function(rmSnap) {

    var messageRef = rootRef.child("messages/" + rmSnap.key);
    messageRef.once('value').then(function(msgSnap) {
        var msg = {
          key: msgSnap.key,
          name: msgSnap.val().name,
          type: $scope.getTypeName(msgSnap.val().type),
          show_only_once: rmSnap.val().show_only_once,
          pre_requisite_message: rmSnap.val().pre_requisite_message
        }

      $scope.$apply(function() {
        console.log(msg); // here I see the object in the console. it is OK
        $scope.messages_by_region.push(msg); // pushing the item
        console.log('----------------');
        console.log($scope.messages_by_region);
      });
    });
  });
}

For more information on this behavior you can also read article describing the problem here

Upvotes: 1

Rodolfo Marcos
Rodolfo Marcos

Reputation: 159

Since you're using async functions (Cosuming of firebase API) you should tell angular to refresh the HTML;

Use

$scope.$diggest()

More information you can find on https://www.sitepoint.com/understanding-angulars-apply-digest/

Upvotes: 1

Related Questions