23

Ho can I get the window width in angularJS on resize from a controller? I want to be able to get it so I can display some div with <div ng-if="windowWidth > 320">

I can get the windowWidth on the initial page load but not on resize...

'use strict';

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

app.controller('mainController', ['$window', '$scope', function($window, $scope){
 var mainCtrl = this;
 mainCtrl.test = 'testing mainController';
  
    // Method suggested in @Baconbeastnz's answer  
    $(window).resize(function() {
      $scope.$apply(function() {
        $scope.windowWidth = $( window ).width();
      });
    });
  
    /* this produces the following error
    /* Uncaught TypeError: mainCtrl.$digest is not a function(…)
    angular.element($window).bind('resize', function(){
        mainCtrl.windowWidth  = $window.innerWidth;
        // manuall $digest required as resize event
        // is outside of angular
        mainCtrl.$digest();
    });  
    */
}]);

// Trying Directive method as suggested in @Yaser Adel Mehraban answer.
/*app.directive('myDirective', ['$window', function ($window) {
     return {
        link: link,
        restrict: 'E'            
     };
     function link(scope, element, attrs){
       angular.element($window).bind('resize', function(){
           scope.windowWidth = $window.innerWidth;
       });    
     }    
 }]);*/
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<body ng-app="app" ng-controller="mainController as mainCtrl">
 <p>{{mainCtrl.test}}</p>
 <hr />
    <p ng-if="windowWidth > 600">The window width is {{windowWidth}}</p>
    <div my-directive ng-if="windowWidth > 320">It works!</div>
</body>

I see in this answer they explain how you can get it from within a directive but how can you get it to work from within a controller?

Community
  • 1
  • 1
Holly
  • 7,462
  • 23
  • 86
  • 140
  • Just wondering, wouldn't it be better to handle resize issues with CSS? – Harke May 09 '17 at 15:23
  • 1
    @Harke There are some use cases where CSS won't cut it. For example, I need to display a large amount of tabular data. Using a `` element makes sense on desktop, but won't work on mobile. Hiding it just with CSS isn't the best idea either, as the data will get rendered twice (even though it only displays once).
    – maxathousand Jun 19 '18 at 20:30

4 Answers4

26

The best way is to use a directive and watch for resize event of the window:

'use strict';

var app = angular.module('plunker', []);

app.directive('myDirective', ['$window', function ($window) {

     return {
        link: link,
        restrict: 'A'           
     };

     function link(scope, element, attrs){

       angular.element($window).bind('resize', function(){
           scope.windowWidth = $window.innerWidth;
       });    
     }    
 }]);

And use it on your div:

<div my-directive ng-if="windowWidth > 320">

Here is a working plunker.

Nick Grealy
  • 24,216
  • 9
  • 104
  • 119
Yaser
  • 5,609
  • 1
  • 15
  • 27
  • this seems like the best approach but it doesn't work in the code snippet. I updated the code snippet in my question with this and it still does not work. – Holly Dec 16 '16 at 10:16
  • The `.bind` function is deprecated, so better to use `.on`. https://docs.angularjs.org/api/ng/function/angular.element – Luke Jul 20 '17 at 19:50
7

Finnally got it working with the below. Took most of the code from https://stackoverflow.com/a/23078185/1814446.

The only difference was for the ng-if to work the directive had to be put on a parent html element.

'use strict';

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

app.controller('mainController', ['$window', '$scope', function($window, $scope){
 var mainCtrl = this;
 mainCtrl.test = 'testing mainController';
}]);

app.directive('windowSize', function ($window) {
  return function (scope, element) {
    var w = angular.element($window);
    scope.getWindowDimensions = function () {
        return {
            'h': w.height(),
            'w': w.width()
        };
    };
    scope.$watch(scope.getWindowDimensions, function (newValue, oldValue) {
      scope.windowHeight = newValue.h;
      scope.windowWidth = newValue.w;
      scope.style = function () {
          return {
              'height': (newValue.h - 100) + 'px',
              'width': (newValue.w - 100) + 'px'
          };
      };
    }, true);

    w.bind('resize', function () {
        scope.$apply();
    });
  }
})
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<body window-size my-directive ng-app="app" ng-controller="mainController as mainCtrl">
  <p>{{mainCtrl.test}}</p>
  <hr />
  <div ng-if="windowWidth > 500">
    <h4 style="margin:5px 0">It works!</h4>
    <p style="margin:0">window.height: {{windowHeight}}</p>        <p style="margin:0">window.width: {{windowWidth}}</p>        <p style="margin:0">{{mainCtrl.test}}</p>
  </div>
</body>
Community
  • 1
  • 1
Holly
  • 7,462
  • 23
  • 86
  • 140
6

Getting the window width on resize isn't anything specific to Angular JS. in fact Angular doesn't provide any capability to do it. It's native javascript, the native window object fires a resize event that you can access. jQuery provides a handy wrapper for this. By using a simple callback in your controller and then updating your double bound windowWidth property on the $scope object you can get the functionality you need without using a directive.

$(window).resize(function() {
  $scope.windowWidth = $( window ).width();
});
williamsandonz
  • 15,864
  • 23
  • 100
  • 186
  • May you explain your answer? – Mistalis Dec 16 '16 at 08:14
  • Getting the window width on resize isn't anything specific to Angular JS. in fact Angular doesn't provide any capability to do it. It's native javascript, the native window object fires a resize event that you can access. jQuery provides a handy wrapper for this. By using a simple callback in your controller and then updating your double bound windowWidth property on the $scope object you can get the functionality you need without using a directive. – williamsandonz Dec 16 '16 at 08:32
  • @Baconbeastnz , thanks but when I tried this in the Code Snippet from my question it does not work, see updated Code Snippet in my question – Holly Dec 16 '16 at 10:21
  • You weren't doing a few things correctly. Have fixed code snippet for you. Basically you need to use $scope instead of 'this'. Also, because the window resize event happens outside the Angular domain, you need to call $scope.apply to manually inform Angular to re-apply changes – williamsandonz Dec 16 '16 at 21:49
4

Just include this code in your controller and you will get the new window width every time.

$scope.windowWidth = $window.innerWidth;
angular.element($window).bind('resize', function(){
    $scope.windowWidth = $window.innerWidth;
    $scope.$apply();
});