Avant-propos
Dans les applications angulaires, la directive ng-model est un élément indispensable. Elle est utilisée pour lier la vue aux données et constitue une partie importante de la magie de la liaison bidirectionnelle. ngModelController est le contrôleur défini dans la directive ng-model. Ce contrôleur contient des services de liaison de données, de validation, de mises à jour CSS, ainsi que de formatage et d'analyse des valeurs. Il n'est pas utilisé pour le rendu DOM ou l'écoute des événements DOM. La logique liée au DOM doit être incluse dans d'autres instructions, puis laisser ces instructions essayer la fonction de liaison de données dans ngModelController.
Remarque : Cet article n'est pas une explication de la documentation de NgModelController, mais est plus pratique. Ensuite, je vous guiderai tout au long du processus pour implémenter une instruction personnalisée et utiliser l'attribut ng-model pour lier les données des deux côtés.
Exemple
Notre application utilise une instruction personnalisée nommée timeDruation
comme suit
<div ng-app="HelloApp" ng-controller="HelloController"> <h1>自定义指令</h1> <time-duration ng-model="test"></time-duration> <h1>默认指令</h1> <input ng-model="test">second </div>
Le code JS est le suivant,
angular.module('HelloApp', []) .directive('timeDuration', TimeDurationDirective); .controller('HelloController', function($scope) { $scope.test = 1; });
, plusieurs unités de temps communes peuvent être spécifiées et des données peuvent être saisies. Enfin, nous obtiendrons le nombre de secondes correspondant. La capture d'écran de sa fonction est la suivante,
Ici, nous lions spécialement la variable de test à nos instructions personnalisées et à nos instructions par défaut respectivement pour observer son effet.
Commande personnalisée
Sans plus tard, jetons un coup d'œil au code
Regardons d'abord le modèle de la commande. Comme le montre l'image ci-dessus, la commande contient une zone de saisie et une zone de sélection déroulante.
<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>
Le modèle est en fait très simple, je n'entrerai donc pas dans les détails ici. Jetons un coup d'œil à la partie logique de cette instruction.
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 } }; }
Nous TODO la méthode de lien de l'instruction temporairement. Il sera progressivement amélioré par la suite.
Permettez-moi d'abord de jeter un œil à la définition de cette directive, qui utilise l'instruction require. En termes simples, la fonction de require est de déclarer une relation de dépendance pour cette directive, indiquant que cette directive dépend de l'attribut contrôleur d'une autre directive.
return { require: '^ngModel' } return { require: '?ngModel' } return { require: '?^ngModel' }
1. La modification du préfixe ^ indique que la recherche est autorisé L'instruction parent de l'instruction actuelle Si le contrôleur de l'instruction correspondante est introuvable, une erreur sera générée.
2. ? signifie transformer cette action requise en option, ce qui signifie que si le contrôleur de l'instruction correspondante ne peut pas être trouvé, aucune erreur ne sera générée.
3. Bien entendu, nous pouvons également utiliser ces deux modifications de préfixe en combinaison.
Par rapport à ?ngModel, nous utilisons ^ngModel plus fréquemment.
Par exemple
<my-directive ng-model="my-model"> <other-directive></other-directive> </my-directive>
À l'heure actuelle, nous utilisons require : ^ngModel dans une autre directive, et ce sera Recherchez automatiquement l'attribut du contrôleur dans la déclaration de ma-directive.
Utiliser NgModelController
Après avoir déclaré require: 'ngModel', le quatrième paramètre sera injecté dans la méthode de lien. Ce paramètre est le contrôleur correspondant à l'instruction dont nous avons besoin. Voici le contrôleur ngModeController de l'instruction intégrée ngModel.
link: function (scope, element, attrs, ngModelCtrl) { // TODO }
$viewValue et $modelValue
Il y a deux attributs très importants dans ngModelController, l'un est appelé $viewValue et l'un s'appelle $modeValue.
L'explication officielle de la signification de ces deux-là est la suivante
$modelValue : la valeur dans le modèle auquel le contrôle est lié.
Si vous avez des doutes sur l'explication officielle ci-dessus, je vais vous donner ici mon explication personnelle.
$viewView est la valeur utilisée par l'instruction pour restituer le modèle, et $modelView est la valeur circulée dans le contrôleur. Plusieurs fois, ces deux valeurs peuvent être différentes.
En plus des deux propriétés $viewValue et $modelValue, il existe deux méthodes pour les gérer. Ce sont respectivement $parses et $formatters.
Le premier consiste à changer $viewValue->$modelValue, tandis que le second est tout le contraire, à $modelValue->$viewValue.
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; });
更多Pratique AngularJS utilisant NgModelController pour la liaison de données相关文章请关注PHP中文网!