1

I am implementing a sample application and I need to implement a follow button similar to the one in Twitter.

I have coded the button as follows,

<button class="btn pull-right{{setButtonStyle(S.Id)}}" 
ng-class="{true:'btn-primary', false:'btn-secondary'}[!S.isFollow]"
ng-click="toggleFollow(S.Id)"> {{!S.isFollow && 'Follow' || 'Unfollow'}}
</button>

The ng-click function handles the DB tables and also toggles the button UI. It is as follows,

$scope.toggleFollow = function (userId) {
    var element = $scope.followIds.indexOf(userId);
    if (element == -1) {
        // Follow user
        $scope.Searched[Sindex].isFollow = !$scope.Searched[Sindex].isFollow; // Toggles the button
        console.log("Follow called"); 
        })
    } else if (element > -1) {
        // Unfollow user
        $scope.Searched[Sindex].isFollow = !$scope.Searched[Sindex].isFollow; // Toggles the button
        console.log("Unfollow called"); 
        })
    }
}

The issue is that the button does not toggle at random. I suspect that the AngularJS digest loop doesn't fire every time the button is clicked.

I know for sure that the Angular function gets called every time when the button is clicked. So only the toggle doesn't fire as expected. So how do I force toggle the button every time it is clicked?

4
  • Try $scope.$apply() in the last function line Commented Sep 2, 2016 at 8:41
  • @Lax Did. I am getting an error that reads Error: [$rootScope:inprog] $apply already in progress Commented Sep 2, 2016 at 9:21
  • Can you post plnkr or something else? Commented Sep 2, 2016 at 9:31
  • I am not familiar with Plunker. Nor do I have any idea about how I can simulate a DB on Plunker to reproduce the exact behavior. Commented Sep 2, 2016 at 10:13

1 Answer 1

1

In your case ,its best to use angular's $apply()

$apply- is used to execute some code at first and then call the $digest() method internally , so that all watches are checked and the corresponding watch listener functions are called.

You make this happen in 2 ways.

First approach- use $apply(), without arguments at the end of your button's implementation code, like below example

$scope.toggleFollow = function (userId) {
   if (element == -1) {

       //...your button's implementation code

   }
   else if (element >= -1) {

      //....your button's implementation code

   }

   //Call $apply()
   $scope.$apply();

}

Second Approach (recomended)- write the button's implementation code inside the function (ie.the function that is passed as a parameter to $apply), so that, the function executes first, and ones function exits, AngularJS will call the $digest() ,so that all watches are checked for the changes in the watched values..

 $scope.toggleFollow = function (userId) {

   //Call $apply() ,passing the function as parameter
   $scope.$apply(function(){
         if (element == -1) {

           //...your button's implementation code

        }
        else if (element >= -1) {

             //....your button's implementation code

        }  
     });
}

For more information on $apply, refer this document. It would give you a better understanding and working of it.

Hope this helps out.

Cheers

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

1 Comment

Method 1 gives me an error that reads Error: [$rootScope:inprog] $apply already in progress after the function executes. Method 2 gives the same error but before the function executes.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.