0

I'm running into an unusual behaviour with ng-switch that I'm not able to figure out. At the top of my page, I have

#content{"ng-switch" => "root.showAlert"}
  %div.alert.ng-cloak#alert{"ng-switch-when" => "true"}
    {{root.alert.message}}
    %div.close
      %a{:href => "#", "ng-click" => "dismissAlert()"}
        =image_tag "icons/icon-close-black.png"

In one of my controllers (highest level) I have the following action

$scope.displayAlert = function(message) {
  $scope.root.alert = {
    message: message
  };
  $scope.root.showAlert = true;

  if (!$scope.$$phase) {
    $rootScope.$digest();
  }
}

$scope.root is defined in the $rootScope so is accessible to everything.

When I change the root.showAlert flag to true, I am expecting to see the alert appear as it should be watching this variable, however it isn't happening immediately, and instead showing when I change something else in the app by performing any other action.

By adding my $rootScope.$digest() it works and displays immediately, but I was wondering why it won't do it on its own?

Dismissing:

$rootScope.dismissAlert = function() {
  $scope.root.showAlert = false;
  delete $scope.root.alert;
}
PaReeOhNos
  • 4,338
  • 3
  • 30
  • 41
  • please provide the dismissAlert() function. My Bet is that you access the wrong scope. – Heinrich May 24 '13 at 14:13
  • I don't have a problem dismissing the alert though, only when displaying it. But as I say, it IS displayed, it just takes either an explicit digest call, or some other action to run – PaReeOhNos May 24 '13 at 14:41
  • okay. It would be nice to see the actual HTML though. Maybe more users would be able to help if you could post HTML instead of haml. And secondly: angular is working on that html result and if haml is doing something strange at this point I couldn't know. – Heinrich May 24 '13 at 14:50

1 Answers1

2

If a call to digest() causes something to change in your UI that otherwise doesn't, it means that the data affecting that UI is being changed in some asynchronous code or some other code that wasn't executed from AngularJS's own context.

All major actions that take place within Angular's built-in functionality (ng-click, $http callbacks, etc.) call scope.$apply (which in turn calls scope.$digest) on the relevant scope to propagate changes throughout the system. If you are changing code from outside Angular's "world," you need to wrap the functionality in a scope.$apply (or call scope.$digest) to do so yourself.

It's possible, in this case, that Angular is running a digest on the scope on which a button is attached, but since you're chanigng data on the root scope, you need to kick off a digest yourself.

See this answer in Databinding in AngularJS for more information.

Community
  • 1
  • 1
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • Ah ok that makes sense. So my `displayAlert` is being called from a callback of a websocket message which I guess is out of angular world. So in there I should wrap the call in a scope.$apply? – PaReeOhNos May 24 '13 at 15:11
  • 1
    Just tested that out and it works perfectly :) I assumed that because my callback was within an angular controller it'd be fine, but I completely forgot that the method was being called from outside of the scope thus it didn't know about it. Working now :D – PaReeOhNos May 24 '13 at 15:15