2

I have a directive to apply some classes on elements based on the window size:

angular.module( 'myApp' ).directive('resizer', ['$window', function ($window) {
    return {
        link: function (scope, elem, attrs) {      
            angular.element($window).on('load resize', function () {
                scope.$apply(function(){
                    scope.isSmall = $window.innerWidth < 800 ? true : false;
                });
            });
            angular.element($window).on('$stateChangeStart', function () {
                scope.$apply(function(){
                    scope.isSmall = $window.innerWidth < 800 ? true : false;
                });
            });
        }
    };
}]);

basically it sets: isSmall to true or false based off the window width. then my ng-click uses this value to apply my classes like so:

<div resizer ng-class="{ 'class1 class2 class': isSmall }"></div>

it works all fine and dandy but I have noticed that if the state is changed in my app to navigate back to the page with this directive applied the styles are not applied to the element. anyone know how I would solve this? I am under the impression I am adding the wrong event handlers; I tried adding a $stateChangeStart to the .on call but so far have not been able to get it working

Eolis
  • 645
  • 2
  • 9
  • 22
  • this could help you http://stackoverflow.com/a/2638357/2435473 – Pankaj Parkar Jul 20 '15 at 21:08
  • That will not work, because I am using an angular App there is only one moment in which the page loads. navigation otherwise does not trigger load events. that did make me aware of another issue though: if the page is navigated away from and back to the classes are reset so its not just on a back button click. I think I need to watch some angular method called when state navigations occur. or store my scope item into the root scope. – Eolis Jul 20 '15 at 21:17

2 Answers2

2

You can probably accomplish what you need using css media queries.

The issue you face is there is no resize or load event during routing change, so just initialize the scope.isSmall when directive fires , not just in the event handler

angular.module('myApp').directive('resizer', ['$window', function ($window) {

    return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
            function setIsSmall() {
                scope.isSmall = $window.innerWidth < 800 ? true : false;
            }
            // when directive fires
            setIsSmall();

            angular.element($window).on('load resize', function () {
                scope.$apply(setIsSmall);
            });
        }
    };
}]);

Note: Might consider also removing this handler during scope destroy to avoid adding it over and over. This may have consequences with other parts of app however if any other listeners are set

  scope.$on('$destroy', function(){
     $window.off('load resize');
   });
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • your solution works! thanks, having the isSmall set in the scope without events initializes it when the state changes and applies the effect. – Eolis Jul 20 '15 at 23:01
0

Try setting the directive scope to true

return {
  restrict: 'A',
  scope: false,
  link: function (scope, elem, attrs) {      
    angular.element($window).on('load resize', function () {
      scope.$apply(function(){
        scope.isSmall = $window.innerWidth < 800 ? true : false;
      });
    });
  }
};

Therefore the scope of the parent will be change and the element in question will receive the change.

Good luck! Hope this helps :)

Reference: http://www.undefinednull.com/2014/02/11/mastering-the-scope-of-a-directive-in-angularjs/

Alex Boisselle
  • 815
  • 9
  • 12
  • tried this solution but it did not apply the effect on state change – Eolis Jul 20 '15 at 23:14
  • Do you have a watcher placed on $window.innerWidth? Check this stack response for a good example of it. You must set your change in that. http://stackoverflow.com/questions/21626357/angularjs-event-on-window-innerwidth-size-change – Alex Boisselle Jul 21 '15 at 01:50