David Gard
David Gard

Reputation: 12047

AngularJS '$watch' not firing when value is changed

I have a web app that must be viewed with the landscape orientation.

To do this, I have created a function that checks the innerWidth and innderHeight, and if the width is greater than the height then happy days. This works perfectly for when I load the page, but I which to also check the orientation when the resize event is fired.

So the flow of my code is -

  1. Upon triggering of the resize event call $scope.getOrienttion()
  2. Calculate the current orientation and return the result
  3. Monitor changes to the value of $scope.getOrienttion() using a watch and update the value of $scope.orientation

Steps 1 and 2 above seem to be working fine, but my watch never detects changes to $scope.getOrienttion() and is only fired upon page load. I must be doing something incorrectly, can anyone please help me to find the problem.

Here is the relevant AngularJS -

christmasApp.controller('bodyCtrl', function($scope, $window){

    angular.element($window).bind('resize', function(){
        console.log('Event triggered');
        $scope.getOrientation();
    });

    $scope.getOrientation = function(){

        var w = $window.innerWidth,
            h = $window.innerHeight;
        var orientation = (w > h) ? 'landscape' : 'portrait'
        console.log('Function triggered - ' + orientation)
        return (w > h) ? 'landscape' : 'portrait';

    };

    $scope.$watch($scope.getOrientation, function(newValue, oldValue){
        $scope.orientation = newValue;
        console.log('Watch triggered - ' + newValue);
    }, true);

});

And here is the HTML that has a conditional class set, depending on the value of $scope.orientation (probably not relevant, but just in case) -

<body <?php body_class(); ?> data-ng-controller="bodyCtrl">

    <div id="orientationMask" data-ng-class="{visible: orientation != 'landscape'}">
        <p>Please turn your device to the <b>landscape</b> orientation.</p>
    </div>

    { Additional code, obscured by the mask if it is show... }

</body>

Upvotes: 2

Views: 1948

Answers (2)

Andr&#233; Kreienbring
Andr&#233; Kreienbring

Reputation: 2509

Why don't you just listen to the orientationchange event like this?

    window.addEventListener("orientationchange", function() {
            switch(window.orientation){  
            case -90:
            case 90:
                $rootScope.orientation = "landscape";
                break; 
            default:
                $rootScope.orientation = "portrait";
            break; 
            };

    }, false);

Upvotes: 1

Pankaj Parkar
Pankaj Parkar

Reputation: 136134

While calling getOrientation from the resize event just executes the getOrientation code, but it don't intimate angular that some thing has change. So you need to call $apply() over $scope to tell angular that to run digest cycle. After calling digest cycle angular will evaluate all the $watchers and the you watcher function will get evaluated.

Actually it seems like getOrientation method call from the resize event is not doing anything related to scope level binding. So you could remove that getOrientation method from there as it seems like calling a code which is doing nothing there.

Code

angular.element($window).bind('resize', function(){
    console.log('Event triggered');
    $scope.getOrientation(); //you could remove this method, as its not modifying any scope
    //will run digest cycle, and the watcher expression will get evaluated
    $scope.$apply(); //you could also use $timeout(function(){}) here run safe digest cycle.
});

Upvotes: 2

Related Questions