2016-06-04 17 views
0

Ich habe ein Paar Direktiven geschrieben, die dazu dienen, eines von mehreren Elementen auf eine größere Größe zu zoomen, wenn auf das Element geklickt wird. Klicken Sie auf das gezoomte Element, um es auf die normale Größe zurückzusetzen. Wenn ein Element gezoomt wird, werden die Schwesterelemente (sie sind alle D3-Diagramme) unsichtbar gemacht. Sie werden wieder sichtbar, wenn das vergrößerte Element aufgehoben wird.Angular: Höhenänderung nicht erkannt

Hier ist, was die HTML wie folgt aussieht:

<chart-container class="chart" chart-height="400" > 
    <h3 class="text-center">Vehicles by year</h3> 
    <div class="text-center" full-screen-toggle> 
     <bar-chart bar-data="{{vehiclesByYear}}" 
        layout="{{vehiclesByYearLayout}}" 
        bar-labels="{$dy: '-.5em', $anchor: 'middle'}"></bar-chart> 
    </div> 
</chart-container> 
<chart-container class="chart" chart-height="400"> 
    <h3 class="text-center">Vehicle speed distribution</h3> 
    <div class="text-center" full-screen-toggle> 
     <pie-chart pie-data="{{aboveBelow}}" 
        layout="{{aboveBelowLayout}}"></pie-chart> 
    </div> 
</chart-container> 

Die Magie im Chart-Container-Element-Richtlinie und der Attribut-Richtlinie Vollbild-Schalter. Letzteres ziert immer ein Kindelement in einem Chart-Container. Hier ist der Code für die beiden Richtlinien:

angular.module('MarkOlbert.fullScreenChart', []).directive('chartContainer', function() { 
    return { 
     restrict: 'E', 
     scope: { 
      chartHeight: '@chartHeight', 
     }, 
     controller: ['$scope', '$element', '$rootScope', function ($scope, $element, $rootScope) { 
      var zoomState = 'normal'; 
      var _self = this; 

      this.changing = false; 
      this.chartHeight = $scope.chartHeight; 

      function unZoom() { 
       $element.css('width', '50%'); 

       _self.changing = true; 
       $rootScope.$broadcast('chart:unzoom'); 
       _self.changing = false; 

       zoomState = 'normal'; 
      } 

      function zoom() { 
       $element.css('width', '100%'); 

       _self.changing = true; 
       $rootScope.$broadcast('chart:zoom'); 
       _self.changing = false; 

       zoomState = 'full'; 
      } 

      $element.on('click', function() { 
       switch (zoomState) { 
        case 'normal': 
         zoom(); 
         break; 

        case 'full': 
         unZoom(); 
         break; 
       } 
      }); 

      $rootScope.$on('chart:unzoom', function() { 
       if (_self.changing) return; 

       $element.css('display', 'block'); 
      }); 

      $rootScope.$on('chart:zoom', function() { 
       if (_self.changing) return; 

       $element.css('display', 'none'); 
      }); 
     }], 
    }; 
}); 

angular.module('MarkOlbert.fullScreenToggle', []).directive('fullScreenToggle', function ($rootScope) { 
    return { 
     restrict: 'A', 
     require: '^^chartContainer', 
     link: function(scope,element,attrs, chartCtrl){ 
      element.css('height', chartCtrl.chartHeight); 

      $rootScope.$on('chart:zoom', function() { 
       if (!chartCtrl.changing) return; 

       element.css('height', 1000); 
      }); 

      $rootScope.$on('chart:unzoom', function() { 
       element.css('height', chartCtrl.chartHeight); 
      }); 
     }, 
    }; 
}); 

In der Bar-Chart-Direktive ich eine einfache Uhr haben, die zu Veränderungen in der Bar-Chart Höhe reagieren sollte:

scope.$watch(function() { return element.height(); }, function() { 
     if (element.height() == 0) return; 
    }, true); 

Im Moment ist es doesn tu nichts, weil ich versuche herauszufinden, warum es nicht aufgerufen wird, wenn der Vollbildmodus die Höhe ändert.

Die show/hide-Funktionalität funktioniert wie vorgesehen. Alle verschiedenen Ereignis-Listener in Chart-Container und Full-Screen-Toggle werden aufgerufen, wenn sie es sollten, und ohne Fehler ausgeführt werden.

Wenn der Diagrammcontainer die Breite seines Elements ändert, wird die Seite wie erwartet aktualisiert. Wenn die Vollbildanzeige jedoch die Höhe des Balkendiagramms ändert, passiert nichts. Die $ watch im Balkendiagramm wird nie ausgelöst.

Antwort

1

.on() ist eine jqLite/jQuery-Methode und löst AngularJS 'Digest Loop nicht automatisch aus.

Was passiert nun:

  1. Element anklickt
  2. Zoom oder Unzoom genannt wird
  3. Element CSS geändert wird
  4. Ereignis wird gesendet
  5. Hörer für die gesendeten Ereignis benachrichtigt werden
  6. Elementhöhe wurde geändert

Da der Digest-Zyklus jedoch nie ausgelöst wurde, wird der Watcher, der die Höhe des Elements überprüft, niemals ausgeführt, und es wird keine Änderung festgestellt.

können Sie $apply verwenden:

$element.on('click', function() { 
    $scope.$apply(function() { 
    switch (zoomState) { 
     case 'normal': 
     zoom(); 
     break; 

     case 'full': 
     unZoom(); 
     break; 
    } 
    }); 
});