Feinheiten von AngularJS: Wählen Sie in der Direktivenvorlage

    Dieser Artikel beschreibt die Lösung eines bestimmten Problems sowie ein Beispiel für die Funktionsweise von $ transclude.

    Die Aufgabe ist folgende: Erstelle eine Direktive, einen Wrapper für select. Angenommen, wir möchten sowohl das Select als auch das Label mit einem Tag auf einmal hinzufügen (dann können wir dort Füllfehler hinzufügen, aber der Einfachheit halber werden wir dies nicht tun). Im Allgemeinen sieht alles auf den ersten Blick einfach aus.

    Machen wir eine Direktive und nennen sie Feld. Wir werden es so benutzen:


    Wir haben uns mehrere Attribute ausgedacht:
    • Titel - Feldname
    • type - Feldtyp (wir werden nur select haben, aber dann plötzlich ...)
    • ng-model - Eine Variable, die den ausgewählten Wert speichert
    • options - Um eine Liste für die Auswahl anzugeben, verwenden wir die Syntax von Anglars ngOptions


    Beachten Sie, dass die Variablen selectedColor, und colorsin dem Beispiel der Umfang Variablen , in denen wir die Richtlinie verwendet. Wir haben sie speziell über die Attribute spezifiziert, damit die Direktive auf sie zugreifen kann.

    Richtliniencode:

    angular.module('directives').directive('field', function () {
    return {
    	//директива - это название тега
    	restrict: 'E', 
    	// то, что мы передали в директиву
    	scope: {
    		ngModel: "=", 
    		title: "@",
    		type: "@",
    		options: "@"
    	},
    	// адрес шаблончика
    	templateUrl: '/tpl/fields/select.html',
    });
    


    Vorlagencode:


    Live: codepen.io/Dzorogh/pen/umCKG?editors=101


    Es scheint, dass alles einfach aussieht und funktionieren sollte. Führen Sie aus, überprüfen Sie im Debugger -

    Es scheint nicht schlecht ... aber wo sind alle Optionen? Warum sind Farben leer (oder undefiniert)?

    Tatsache ist, dass, wenn wir den scope-Parameter in der Direktive angeben, der gesamte Inhalt der Direktive in einen Steinmauer-isolierten Bereich umgewandelt wird. In diesem isolierten Bereich können die Benutzer keinen externen Bereich sehen. Dementsprechend werden jedoch alle Variablen ( ngModel, type, title, options), die wir für den Anweisungsparameter angegeben haben, zu unserem isolierten Gültigkeitsbereich hinzugefügt und an externe Variablen „gebunden“.

    Und hier können wir das Problem sehen - wir haben nicht colorszu diesen Variablen hinzugefügt . Zu Recht sollte die Direktive natürlich nicht wissen, welche Art von Array wir dort verwenden möchten. Wir haben bereits angegeben, dass wir dieses Array verwenden, indem wir es in das options-Attribut schreiben.

    Um auf das Array zugreifen zu können, müssen wir mindestens den Namen der Variablen kennen. Daher ist die beste Option, Optionen zu analysieren. Der Quellcode von angular.js hilft uns hier, es gibt eine Regelmäßigkeit für ngOptions.

    Aber warten Sie, auch nachdem Sie den Variablennamen aus dem äußeren Gültigkeitsbereich erhalten haben, wie können wir ihn einfügen?

    Eigentlich am interessantesten


    Um externe Variablen nach der Initialisierung der Direktive an interne zu binden, müssen Sie so etwas wie "$ transclude" verwenden. Durch Aufrufen dieser Funktion erhalten Sie Zugriff auf einen externen Gültigkeitsbereich. Von dort können Sie einfach eine beliebige Variable abrufen und Anweisungen an den Gültigkeitsbereich übergeben.

    Neue Richtlinie, mit regulären und transclude:
    .directive('field', function() {
      // позаимствовано из исходников angularjs
      var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/;
      };
      return {
        restrict: 'E',
        scope: {
          ngModel: "=",
          type: "@",
          title: "@",
          options: "@"
        },
        // "Включаем" возможность использовать трансклюд
        transclude: true,
        templateUrl: '/fields/select.html',
        // $transclude всегда идет 5м параметром.
        link: function (scope, element, attrs, controller, $transclude) {
          if (scope.type == 'select') {
            // Парсинг названия массива значений
            var parsedOptions = attrs.options.match(NG_OPTIONS_REGEXP);
            // убираем фильтры (они пишутся после | )
            var optionsArray = /^(.*) \|/.exec(parsedOptions[7]) || parsedOptions[7];
            // optionsArray - название (только название) массива, в котором содержится список значений.
            // чтобы получить к нему доступ, нужно взять его из общего Scope
            // (того, где появилась директива) и добавить в наш.
            $transclude(function (clone, $outerScope) {
              scope[optionsArray] = $outerScope[optionsArray];
            });
          }
        } 
      }
    });
    


    Letzte Option in CodePen: codepen.io/Dzorogh/pen/gBbyI

    Jetzt auch beliebt: