richbai90
richbai90

Reputation: 5204

$watch fires only on first update of window.innerWidth

I'm trying to setup my app to watch the window.innerWidth property and add a property to the $scope based on that width. It works the first time, but not on any resize after that. Is the $digest method not being called? If so why not?

Module

//Initialize angular module include route dependencies

var app = angular.module("selfservice", ['ngRoute']);

app.config(function ($routeProvider) {
   $routeProvider
       .when('/', {
           templateUrl:"partials/login.html",
           controller:"login"
       });
});

Controller

app.controller("login", ['$scope', function ($scope) {


$scope.$watch(

    function () {
        return window.innerWidth;
    },

    function (newval, oldval) {
        if (newval < 700) {
            $scope.classExpand = 'expand';
        } else {
            $scope.classExpand = '';
        }

        console.log(newval, oldval);
    });



}]);

View

<div class="small-12 column">
            <a href="/portal" class="button radius large {{classExpand}}">Sign In</a>
</div>

This works the first time, if I refresh the screen after resizing it, the expand class is applied, but when I resize it, nothing happens, the console.log function doesn't even fire

Upvotes: 1

Views: 1207

Answers (1)

Marc Kline
Marc Kline

Reputation: 9409

Resizing the window doesn't cause Angular to re-run a $digest loop, so window.innerWidth's value is checked only when something else causes it.

You should instead use a directive (ie. don't do this work in your controller), binding to the window.onresize event:

.directive('watchResize', function(){
  return {
    restrict: 'A',
    link: function(scope, elem, attr) {
      angular.element(window).on('resize', function(){
        scope.$apply(function(){
          scope.classExpand = (window.innerWidth < 700) ? 'expand' : '';
        });
      });
    }
  }
});

In this case, you call scope.$apply. This causes the $digest loop to run following this event, which is outside of the Angular context.

You can use this directive to decorate an element on the same scope as the variable you're changing:

<div watch-resize>
  {{ classExpand }}
</div>

Demo (best viewed full-screen)

Upvotes: 2

Related Questions