1

I'm monitoring a CSS style and updating a variable in the scope that's based on that CSS style's value. It works the first time around but when the browser is resized, the scope gets updated but ng-style does not update with the new scope parameter.

JS:

.directive('monitorStyle', function() {
        return {
            link: function(scope, element, attrs) {
                scope[attrs.updateVariable] = $(element).css(attrs.monitorStyle);
                angular.element(window).on('resize', function() {
                    scope[attrs.updateVariable] = $(element).css(attrs.monitorStyle);
                });

            }
        }
    })

HTML:

<p class="text" monitor-style="font-size" update-variable="textHeight">Press "<img class="mini up" src="img/select-arrow.png" src="Up" ng-style="{'height': textHeight}">

I'm trying to do this outside of the controller because that's what people recommend. Why is ng-style not updating when the scope gets updated?

  • Have you tried using $(window).resize instead of angular? And if you wanted to achieve this by angular then below link will help you. http://stackoverflow.com/questions/23044338/window-resize-directive – J-D Oct 16 '15 at 04:44
  • Probably this answer may help you http://stackoverflow.com/a/25111105/2353403 – Coder Oct 16 '15 at 05:05
  • Thank you, Damnien answered below. The trick was adding scope.$apply(); inside of the resize event in the directive – ProfessorManhattan Oct 16 '15 at 11:57

2 Answers2

4

The window event isn't an angular event, so angular don't know he have to update the model/scope. You have to add scope.$apply() to tell angular to refresh it :

angular.element(window).on('resize', function() {
    scope[attrs.updateVariable] = $(element).css(attrs.monitorStyle);
    scope.$apply();
});

Data bindig only works when your model is updated with angular event like $http, $timeout, ng-click, ...

A great article about it : http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

Damien
  • 3,915
  • 1
  • 17
  • 18
  • 1
    Note: I was trying this but applying scope.$apply(); outside of the angular.element(window) resize and it was giving me that $digest in progress error you get for calling a scope.$apply too early – ProfessorManhattan Oct 16 '15 at 11:55
0

Yo, I made this sick solution.

So if you want to watch styles (even an array of them on a particular element) and then send their values to the $scope you can use this JS:

.directive('monitorStyle', function($timeout) {
    return {
        link: function(scope, element, attrs) {
            function addToScope() {
                var updateVariable = attrs.updateVariable.split(',');
                var monitorStyle = attrs.monitorStyle.split(',');
                for (var i = 0; i < updateVariable.length; i++) {
                    scope[updateVariable[i]] = $(element).css(monitorStyle[i]);
                }
            }
            addToScope();
            angular.element(window).on('resize', function() {
                addToScope();
                scope.$apply();
            });
        }
    }
})

And apply it like this:

<h2 monitor-style="font-size,line-height" update-variable="headerHeight,headerLineHeight">

This will update the $scope on initialization and on window resizes. You can of course modify it to your own purpose.

Each time the $scope changes you can update other styles like this:

<div ng-style="{'height': headerHeight, 'line-height': headerLineHeight}">