Mike Mike - 1 month ago 11
AngularJS Question

Modifying elements with same directive

I have several elements in a container. One of the rows has two icons in it: zoom in and zoom out. When you click Zoom In, I'd like all the row's widths to grow.

<div id="events">
<year>year 1</year>
<year>year 2</year>
<year>year 3</year>
<year>year 4</year>

<div id="scaling">
<md-icon aria-label="Zoom In" class="material-icons" ng-click="zoomIn()">zoom_in</md-icon>
<md-icon aria-label="Zoom Out" class="material-icons" ng-click="zoomOut()">zoom_out</md-icon>
</div>
</div>


I have a year directive:

angular.module("app").directive("year", ['$rootScope', function ($rootScope) {
return {
link: function($scope, element, attr) {

var events = element;

$scope.zoomIn = function(ev) {

console.log('zoomin');
$scope.zoom = $scope.zoom + $scope.scale;

if($scope.zoom < 100) { $scope.zoom = 100; }

events.html($scope.zoom);

events.css({
'width': $scope.zoom + '%'
});
}

$scope.zoomOut = function(ev) {
$scope.zoom = $scope.zoom - $scope.scale;

if($scope.zoom < 100) { $scope.zoom = 100; }

events.css({
'width': $scope.zoom + '%'
});
}
}
}
}]);


However the width is only applied to the very last year element. Why is that?

Answer

You are overwriting the scope every time. So each instance of your year directive is clobbering the zoomIn and zoomOut methods each time it is instantiated.

Normally you could solve this by using a new or isolate scope in your directive definition object:

//new scope
{
  scope: true
}

//isolate scope
{
  scope: {}
}

However, since you want to bind click handlers outside your individual year directives you will have to do something else.

A better solution would be to pass in the attributes and simply respond to their changes:

return {
   scope: {
      zoom: '='
   },
   link: function(scope, elem, attrs){

      scope.$watch('zoom', function(){
         //Do something with 'scope.zoom'
      });

   }
};

Now your external zoomIn and zoomOut functions can just modify some zoom property on the parent scope, and you can bind your year components to that.

<year zoom="myZoomNumber"></year>