Angular Directive Link Function Event Binding

Eigentlich komme ich aus keinem AngularJS Training raus ohne das nicht ein Teilnehmer ein auf den ersten Blick seltsame Scope Binding Frage in Zusammenhang mit Direktiven stellt.

Vor einiger Zeit habe ich mir eine Direktive geschrieben, die einen Submit Button um die Sicherheitsabfrage “Wirklich löschen ergänzt?”. Ein Click Counter auf dem Viewmodel Scope zeigt an, ob der Benutzer OK oder Cancel im PopUp Dialog gewählt hat.

   1:   <div ng-app="App" ng-controller="myController">
   2:          clicked {{count}}<br />
   3:          <button type="button" pp-confirm-click="myclick()" pp-confirm-message="Wirklich?">
löschen</button>
   4:      </div>

Der ziemlich knappe Angular JavaScript Code definiert einen Controller für die eigentliche myClick Methode. Zusätzlich wird eine Direktive als Attribut (restrict) definiert, das eine click Methode an den Button hängt.  Um die Umleitung an den Scope zu delegieren, kommt $apply auf dem so referenzierten scope des Controllers zum Einsatz,

   1:   angular.module('App', [])
   2:          .controller('myController', ['$scope', function ($scope)
   3:          {
   4:              $scope.count = 0;
   5:              $scope.myclick = function () {
   6:                  $scope.count++;
   7:              };
   8:          }])
   9:   
  10:          .directive('ppConfirmClick', [ function(){
  11:              return {
  12:                  restrict: 'A',
  13:                     link: function (scope, element, attrs) {
  14:                      element.bind('click', function () {
  15:                          var message = attrs.ppConfirmMessage;
  16:                          if (message && confirm(message)) {
  17:                               scope.$apply(attrs.ppConfirmClick);
  18:                          }
  19:                      });
  20:                  }
  21:   
  22:              }
  23:          }
  24:          ]);

Nun besteht die in diesem Fall akademische Möglichkeit, die direktive um ein HTML Template zu erweitern mit dem Schlüssel Template bzw TemplateUrl im Rückgabe Objekt. Dazu wird es aber auch nötig eventuell einen eigenen und definierten Scope zu nutzen. Eine Bindung im HTML Template auf Werte soll ja nach außen gekapselt werden.

Wenn man nun aber den scope in folgender Form einfügt, kann auch nicht mehr auf eine Methode des Parent Scopes zugegriffen werden.

   1:  .directive('ppConfirmClick', [ function(){
   2:              return {
   3:                  ...
   4:                  scope: { ... },

Um den Scope von Parent auf den aktuellen zu kopieren, stehen für Eigenschaften in der Direktive Anweisungen wie =,@,& zur Verfügung. Das bedeutet, das im Attribut der Nutzung der Direktive gesteuert wird, was an diese als Parameter zur Verfügung gestellt werden soll. In Zeile 3 des HTML Code Blockes eben die Methode myclick(). Nun kommt das & Steuerzeichen zum Einsatz, das für Methodennamen genutzt wird und erzeugt so im privaten Scope der Direktive eine Referenz auf die Methode. Diese kann dann per Apply im scope angestoßen werden.

   1:   scope: { ppConfirmClick: '&' },
   2:   link: function (scope, element, attrs) {
   3:                   element.bind('click', function () {
   4:                     var message = attrs.ppConfirmMessage;
   5:                     if (message && confirm(message)) {
   6:                            scope.$apply(scope.ppConfirmClick);
Kommentare sind geschlossen