Mawg
Mawg

Reputation: 40159

Scope function executes but the HTML never changes

Scope of an AngularJS scope variable

I have this in my HTML

{{searchDialog.visible}}

and this in my controller

$scope.searchDialog = {'visible' : false};   // initialize

$scope.MarkerClicked = function(e)
{
    $scope.searchDialog.visible = true;
}

These are the only mentions of $scope.searchDialog. I beakpoint the $scope.MarkerClicked function and watch the value toggle to true, but the HTML never changes.

What am I doing wrongly? Is there a scope problem (no pun intended)?

Aha!! $scope.MarkerClicked is a callback from clicking a Leaflet map marker

var marker = L.marker(pubLatLng,
    {
        draggable: false,
        title: title,
        icon: new L.DivIcon({
            html: '<img class="my-div-image" src="js/3rd_party/leaflet/images/'
                       + iconImage + '" />'
                + '<span style="color:red">' + companyName + '</span>',
        })
    }).addTo($scope.map).on('click', $scope.MarkerClicked);

Is that somehow causing my problem? I can't see how, as the marker is added in a $scope function and the callback also handled in a $scope function.

Upvotes: 0

Views: 55

Answers (2)

georgeawg
georgeawg

Reputation: 48968

Events created by third-party applications need to be brought into the AngularJS framework using $scope.$apply:

var marker = L.marker(pubLatLng,{
    draggable: false,
    title: title,
    icon: new L.DivIcon({
        html: '<img class="my-div-image" src="js/3rd_party/leaflet/images/'
                   + iconImage + '" />'
            + '<span style="color:red">' + companyName + '</span>',
    })
}).addTo($scope.map).on('click', function(e) {
    $scope.$apply(function() {
        $scope.MarkerClicked(e)
    });
});

AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc... You can also use $apply() to enter the AngularJS execution context from JavaScript.

AngularJS Developer Guide - Integration with the browser event loop

Upvotes: 1

Sarvesh Mahajan
Sarvesh Mahajan

Reputation: 924

This problem is related to Angular Digest Cycle, as MarkerClicked method was called, but it was outside the scope of Angular Digest Cycle, so You have to explicitly called digest cycle.

And to solve this issue please take a look at below code snippet, where if we don't add $scope.$apply(), $scope.message will not get updated, and after adding $scope.$apply() in below example which automatically triggers $rootScope.$digest(). As a result, the watchers are fired as usual and the view updates.

/* What happens with $apply */ 
angular.module('myApp',[]).controller('MessageController', function($scope) {
    
      $scope.getMessage = function() {
        setTimeout(function() {
          $scope.$apply(function() {
            //wrapped this within $apply
            $scope.message = 'Fetched after 3 seconds'; 
            console.log('message:' + $scope.message);
          });
        }, 2000);
      }
      
      $scope.getMessage();
    
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js"></script>

<body ng-app="myApp">
  <div ng-controller="MessageController">
    Delayed Message: {{message}}
  </div>  
</body>

Upvotes: 1

Related Questions