前書き
Angular アプリケーションでは、ng-model ディレクティブは不可欠な部分であり、ビューをデータにバインドするために使用され、双方向バインディング マジックの重要な部分です。 ngModelController は、ng-model ディレクティブで定義されたコントローラーです。このコントローラーには、データ バインディング、検証、CSS 更新、値の書式設定と解析のためのサービスが含まれています。 DOM のレンダリングや DOM イベントのリッスンには使用されません。 DOM 関連のロジックは他の命令に含める必要があり、これらの命令で ngModelController のデータ バインディング関数を試行させます。
注: この記事は NgModelController ドキュメントの説明ではありませんが、より実践的なものです。次に、カスタム命令を実装し、ng-model 属性を使用して両側のデータをバインドするプロセス全体を説明します。
例
私たちのアプリは次のように timeDruation
という名前のカスタムディレクティブを使用します
<div ng-app="HelloApp" ng-controller="HelloController"> <h1>自定义指令</h1> <time-duration ng-model="test"></time-duration> <h1>默认指令</h1> <input ng-model="test">second </div>
JSコードは次のとおりです。
angular.module('HelloApp', []) .directive('timeDuration', TimeDurationDirective); .controller('HelloController', function($scope) { $scope.test = 1; });
そのようなことをしてくださいつまり、いくつかの一般的な時間単位を指定してデータを入力できます。最後に、対応する秒数を取得します。その関数のスクリーンショットは次のとおりです。
ここでは、テスト変数をカスタム命令とデフォルト命令にそれぞれ特別にバインドして、その効果を観察します。
カスタムコマンド
早速、コードを見てみましょう
まず、コマンドのテンプレートを見てみましょう。上の図からわかるように、コマンドには入力ボックスとドロップダウン選択ボックスが含まれています。
<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>
このテンプレートは実際には非常にシンプルなので、ここでは詳しく説明しません。この命令の論理的な部分を見てみましょう。
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 } }; }
指示のリンク方法はとりあえずTODOです。今後徐々に改善していきます。
まず、require ステートメントを使用するこのディレクティブの定義を見てみましょう。簡単に言えば、require の機能は、このディレクティブの依存関係を宣言し、このディレクティブが別のディレクティブのコントローラー属性に依存していることを示すことです。
ここでは、require の派生的な使用法について簡単に説明します。
require の前に修辞的量指定子を追加できます。たとえば、
return { require: '^ngModel' } return { require: '?ngModel' } return { require: '?^ngModel' }
1. ^ 接頭辞の変更は、対応する命令のコントローラーの場合、現在の命令の親命令を検索できることを示します。見つからない場合は、エラーがスローされます。
2. ? は、require アクションをオプションに変えることを意味します。これは、対応する命令のコントローラーが見つからない場合でも、エラーはスローされないことを意味します。
3. もちろん、これら 2 つのプレフィックス変更を一緒に使用することもできます。
?ngModel と比較して、^ngModel をより頻繁に使用します。
例:
<my-directive ng-model="my-model"> <other-directive></other-directive> </my-directive>
このとき、other-directive で require: ^ngModel を使用します。これにより、my-directive ディレクティブ宣言内のコントローラー属性が自動的に検索されます。
NgModelController を使用する
require: 'ngModel' を宣言した後、4 番目のパラメーターがリンク メソッドに挿入されます。このパラメーターは、必要な命令に対応するコントローラーです。これは、組み込み命令 ngModel のコントローラー ngModeController です。
link: function (scope, element, attrs, ngModelCtrl) { // TODO }
$viewValue と $modelValue
ngModelController には 2 つの非常に重要なプロパティがあり、1 つは $viewValue と呼ばれ、もう 1 つは $modeValue と呼ばれます。これらの2つの意味の公式の説明は次のとおりです。$ ViewValue:実際の文字列値をビューに使用します。
$viewView はテンプレートをレンダリングする命令によって使用される値であり、$modelView はコントローラー内で循環される値です。多くの場合、これら 2 つの値は異なる場合があります。
たとえば、ページに日付を表示すると、「2015 年 10 月 20 日」のような文字列が表示されますが、コントローラー内のこの文字列に対応する値は、JavaScript Date オブジェクトのインスタンスである可能性があります。
$formatters と $parses
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; });
更多データ バインディングに NgModelController を使用した AngularJS の実践相关文章请关注PHP中文网!