Vorwort
In Angular-Anwendungen ist die ng-model-Direktive ein unverzichtbarer Bestandteil. Sie wird verwendet, um die Ansicht an Daten zu binden, und ist ein wichtiger Teil der bidirektionalen Bindungsmagie. ngModelController ist der in der ng-model-Direktive definierte Controller. Dieser Controller enthält Dienste für die Datenbindung, Validierung, CSS-Aktualisierungen sowie die Formatierung und Analyse von Werten. Es wird nicht zum DOM-Rendering oder zum Abhören von DOM-Ereignissen verwendet. DOM-bezogene Logik sollte in andere Anweisungen einbezogen werden. Lassen Sie diese Anweisungen dann die Datenbindungsfunktion in ngModelController ausprobieren.
Hinweis: Dieser Artikel ist keine Erklärung der NgModelController-Dokumentation, sondern praktischer. Als Nächstes werde ich Sie durch den gesamten Prozess führen, um eine benutzerdefinierte Anweisung zu implementieren und das ng-model-Attribut zum Binden von Daten auf beiden Seiten zu verwenden.
Beispiel
Unsere App verwendet eine benutzerdefinierte Direktive namens timeDruation
wie folgt
<div ng-app="HelloApp" ng-controller="HelloController"> <h1>自定义指令</h1> <time-duration ng-model="test"></time-duration> <h1>默认指令</h1> <input ng-model="test">second </div>
Der JS-Code lautet wie folgt:
angular.module('HelloApp', []) .directive('timeDuration', TimeDurationDirective); .controller('HelloController', function($scope) { $scope.test = 1; });
Es können mehrere gemeinsame Zeiteinheiten angegeben und Daten eingegeben werden. Schließlich erhalten wir die entsprechende Anzahl an Sekunden. Der Screenshot seiner Funktion lautet wie folgt:
Hier binden wir die Testvariable speziell an unsere benutzerdefinierten Anweisungen bzw. Standardanweisungen, um ihre Wirkung zu beobachten.
Benutzerdefinierte Anweisungen
Werfen wir ohne Umschweife einen Blick auf den Code
Schauen wir uns zunächst die Vorlage der Anweisung an. Wie aus dem Bild oben ersichtlich ist, enthält der Befehl ein Eingabefeld und ein Dropdown-Auswahlfeld.
<div class="time-duration"> <input ng-model='num'> <select ng-model='unit'> <option value="seconds">Seconds</option> <option value="minutes">Minutes</option> <option value="hours">Hours</option> <option value="days">Days</option> </select> </div>
Die Vorlage ist eigentlich sehr einfach, daher werde ich hier nicht auf Details eingehen. Werfen wir einen Blick auf den logischen Teil dieser Anleitung.
function TimeDurationDirective() { var tpl = '....'; // 指令模板代码就是上面的内容,这里就不复制了。 return { restrict: 'E', replace: true, template: tpl, require: 'ngModel', scope: {}, link: function(scope, element, attrs, ngModelController) { var multiplierMap = { seconds: 1, minutes: 60, hours: 3600, days: 86400 }; var multiplierTypes = ['seconds', 'minutes', 'hours', 'days']; // TODO } }; }
Wir TODO die Link-Methode der Anleitung vorübergehend. Es wird später schrittweise verbessert.
Lassen Sie mich zunächst einen Blick auf die Definition dieser Direktive werfen, die die require-Anweisung verwendet. Einfach ausgedrückt besteht die Funktion von require darin, eine Abhängigkeitsbeziehung für diese Direktive zu deklarieren, was angibt, dass diese Direktive vom Controller-Attribut einer anderen Direktive abhängt.
return { require: '^ngModel' } return { require: '?ngModel' } return { require: '?^ngModel' }
1. Die Modifikation des Präfixes ^ gibt an, dass gesucht wird ist zulässig. Die übergeordnete Direktive der aktuellen Direktive. Wenn der Controller für die entsprechende Direktive nicht gefunden werden kann, wird ein Fehler ausgegeben.
2. ? bedeutet, dass diese erforderliche Aktion in eine Option umgewandelt wird, was bedeutet, dass kein Fehler ausgegeben wird, wenn der Controller für die entsprechende Anweisung nicht gefunden werden kann.
3. Natürlich können wir diese beiden Präfixmodifikationen auch in Kombination verwenden.
Im Vergleich zu ?ngModel verwenden wir ^ngModel häufiger.
Zum Beispiel
<my-directive ng-model="my-model"> <other-directive></other-directive> </my-directive>
Zu diesem Zeitpunkt verwenden wir require: ^ngModel in other-directive, und das wird auch so sein Suchen Sie automatisch nach dem Controller-Attribut in der Deklaration von my-directive.
Verwenden Sie NgModelController
Wenn wir require: 'ngModel' deklarieren, wird der vierte Parameter in die Link-Methode eingefügt. Dieser Parameter ist der Controller, der der von uns benötigten Anweisung entspricht. Hier ist der Controller ngModeController der integrierten Anweisung ngModel.
link: function (scope, element, attrs, ngModelCtrl) { // TODO }
$viewValue und $modelValue
Es gibt zwei sehr wichtige Attribute in ngModelController, eines ist heißt $viewValue und einer heißt $modeValue.
Die offizielle Erklärung der Bedeutung dieser beiden lautet wie folgt
$modelValue: Der Wert in der Modell, an das die Steuerung gebunden ist.
Wenn Sie Zweifel an der obigen offiziellen Erklärung haben, gebe ich Ihnen hier meine persönliche Erklärung.
$viewView ist der Wert, den die Anweisung zum Rendern der Vorlage verwendet, und $modelView ist der im Controller zirkulierende Wert. Oftmals können diese beiden Werte unterschiedlich sein.
Zusätzlich zu den beiden Eigenschaften $viewValue und $modelValue gibt es zwei Methoden für deren Handhabung. Sie sind $parses bzw. $formatters.
Ersteres besteht darin, $viewValue->$modelValue zu ändern, während Letzteres genau das Gegenteil ist und in $modelValue->$viewValue geändert wird.
1、在外部控制器中(即这里的HelloApp的controller),我们通过ng-model="test"将test变量传入指令time-duration中,并建立绑定关系。
2、在指令内部,$modelValue其实就是test值的一份拷贝。
3、我们通过$formatters()方法将$modelValue转变成$viewValue。
4、然后调用$render()方法将$viewValue渲染到directive template中。
5、当我们通过某种途径监控到指令模板中的变量发生变化之后,我们调用$setViewValue()来更新$viewValue。
6、与(4)相对应,我们通过$parsers方法将$viewValue转化成$modelValue。
7、当$modelValue发生变化后,则会去更新HelloApp的UI。
完善指令逻辑
按照上面的流程,我们先来将$modelValue转化成$viewValue,然后在指令模板中进行渲染。
// $formatters接受一个数组 // 数组是一系列方法,用于将modelValue转化成viewValue ngModelController.$formatters.push(function(modelValue) { var unit = 'minutes', num = 0, i, unitName; modelValue = parseInt(modelValue || 0); for (i = multiplierTypes.length-1; i >= 0; i--) { unitName = multiplierTypes[i]; if (modelValue % multiplierMap[unitName] === 0) { unit = unitName; break; } } if (modelValue) { num = modelValue / multiplierMap[unit]; } return { unit: unit, num: num }; });
最后返回的对象就是$viewValue的value。(当然$viewValue还会有其他的一些属性。)
第二步,我们调用$render方法将$viewValue渲染到指令模板中去。
// $render用于将viewValue渲染到指令的模板中 ngModelController.$render = function() { scope.unit = ngModelCtrl.$viewValue.unit; scope.num = ngModelCtrl.$viewValue.num; };
第三步,我们通过$watch来监控指令模板中num和unit变量。当其发生变化时,我们需要更新$viewValue。
scope.$watch('unit + num', function() { // $setViewValue用于更新viewValue ngModelController.$setViewValue({ unit: scope.unit, num: scope.num }); });
第四步,我们通过$parsers将$viewValue->$modelValue。
// $parsers接受一个数组 // 数组是一系列方法,用于将viewValue转化成modelValue ngModelController.$parsers.push(function(viewValue) { var unit = viewValue.unit; var num = viewValue.num; var multiplier; multiplier = multiplierMap[unit]; return num * multiplier; });
更多AngularJS übt die Verwendung von NgModelController für die Datenbindung相关文章请关注PHP中文网!