ディレクティブの拡張とレイアウト

ディレクティブについては多く書かれていますが、それらを正しく記述する方法についてはほとんど書かれていません。 私の経験を共有します。



よく書かれたディレクティブは





パスワードフィールドの例を使用して各項目を分析しましょう(誰もが目でフィールドを知っていると思います)



画像



<input ng-model="user.password" ng-minlength="6" form-password form-error="  6 ">
      
      







いくつのディレクティブが使用されていますか?

実際、それらの7つがあります。



  1. ng-model



  2. ng-minlength



  3. form-password



    入力を独自のテンプレートに置き換え、目をクリックしたときにフィールドタイプ(パスワード/テキスト)を変更します
  4. form-error



    error-パスワードの長さが足りない場合、エラーのツールチップを表示します
  5. form-error-tooltip



    要素の上に指定されたテキストを含むツールチップを表示します
  6. form-error-tooltip-template



    ヘルパーディレクティブ
  7. tooltip



    展開するAngular Bootstrapライブラリのディレクティブ




再定義



angular-ui.github.io/bootstrap/#/tooltipのツールチップとそのソースコードを検討してください。



最初に目を引くのは、個別のservice $tooltip



で取り出されるディレクティブ定義オブジェクトです。 このため、ディレクティブは次のように定義されます。



 .directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); }])
      
      







2つ目は、ツールチップテンプレートがないことです。 代わりに、 directiveName +'-popup '



という名前のdirectiveName +'-popup '



が作成および構成されている要素がdirectiveName +'-popup '



されます(この場合、directiveName = tooltip)。



 '<div '+ directiveName +'-popup '+ 'title="'+startSym+'tt_title'+endSym+'" '+ 'content="'+startSym+'tt_content'+endSym+'" '+ 'placement="'+startSym+'tt_placement'+endSym+'" '+ 'animation="tt_animation" '+ 'is-open="tt_isOpen"'+ '>'+ '</div>';
      
      







以下でこのディレクティブを見つけます(テンプレートと呼びましょう):



 .directive( 'tooltipPopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-popup.html' }; })
      
      







template / tooltip / tooltip-popup.htmlで、ついにツールチップテンプレートが見つかります。



読者として、1つの機能コードを使用して、さまざまなテンプレートを使用して任意の数のツールヒントディレクティブを作成できるように、このような猫が必要であると推測したでしょう。



テンプレートでエラーのヒントを表示するためのディレクティブを作成しましょう。 要素でopen



イベントがトリガーされるとツールチップが表示され、次の場合は非表示になります-close



 app.directive('formErrorTooltip', function($tooltip) { return $tooltip('formErrorTooltip', 'formErrorTooltip', 'open'); });
      
      







1行。 かっこいい



form-error-tooltip-popupという名前のテンプレートディレクティブはテンプレートとして使用されます(directiveName + '-popup'を思い出してください)。 tooltip-popupをコピーして事前に作成し、テンプレートの名前とパスを置き換えます。



open



イベントとclose



イベントはサポートされていませんが、問題ではありません。 開発者は、独自のイベントを追加することを可能にしました。

 app.config(function($tooltipProvider) { $tooltipProvider.setTriggers({'open': 'close'}); });
      
      







延長



そのため、要素の上にform-error-tooltip



を示すform-error-tooltip



がありform-error-tooltip



。 入力する文字が少ない場合にエラーを表示させましょう(このプロジェクトでは、サーバーのエラーを含むエラーの処理方法を教えることは難しくありません)。 最初のform-error



を拡張するform-error



ディレクティブを作成しform-error







 app.directive('formError', function($compile, $interpolate, $injector) { return { terminal: true, priority: 100, scope: true, compile: function compile(tElement, tAttrs) { var startSym = $interpolate.startSymbol(), endSym = $interpolate.endSymbol(), self = this; tElement.attr('form-error-tooltip', startSym + 'message' + endSym); angular.forEach(tAttrs.$attr, function(value, attr) { var ddo = $injector.has(attr + 'Directive') ? $injector.get(attr + 'Directive')[0] : {}; if (ddo.terminal && ddo.priority >= self.priority) { tElement.removeAttr(value); } }); return function(scope, element, attrs, controller) { $compile(element)(scope); var ngModelCtrl = element.controller('ngModel') element.on('input blur change', checkValidity); function checkValidity() { if (ngModelCtrl.$error.minlength) { setError(attrs.formError); } else if (element.scope() && element.scope().tt_isOpen) { //avoid tooltip bug element.triggerHandler('close'); } } function setError(message) { scope.message = message; scope.$digest(); //set message to tooltip element.triggerHandler('open'); } }; } }; });
      
      







コードからわかるように、 form-error-tooltip



ディレクティブを要素に追加し、 form-error-tooltip



有無に応じて、その要素でopen



イベントとclose



イベントをトリガーしopen



。 しかし、彼女はどうやってそれをしますか? 優先事項がすべてです。



terminal: true, priority: 100



がインストールされているためterminal: true, priority: 100



他の非ターミナルディレクティブまたは優先度の低いディレクティブは実行されません。 つまり、 ng-if, ng-repeat, ng-include



などのみが、このディレクティブの前に実行されます。 アイテムを表示するかどうかを決定するディレクティブ。



次に、属性form-error-tooltip={{message}}



追加し、ディレクティブ自体を含む優先度の高い(既に完了している)ディレクティブの属性を削除します。これにより、無期限に実行されないように、要素を再コンパイルします。 これで、ツールチップ表示ディレクティブを含む残りのすべてのディレクティブが実行され、競合は発生しません。



レイアウト



同様に、要素を独自のテンプレートで置き換える必要があるパスワードディレクティブを続行します。



 app.directive('formPassword', function($compile, $injector) { return { restrict: 'AE', terminal: true, priority: 200, templateUrl: 'passwordTemplate.html', replace: true, scope: true, compile: function(tElement, tAttrs) { var input = tElement.find('input')[0], self = this; angular.forEach(tAttrs.$attr, function(value, attr) { var ddo = $injector.has(attr + 'Directive') ? $injector.get(attr + 'Directive')[0] : {}; if (attr !== 'type' && attr !== 'class' && attr !== 'formPassword' && (!ddo.terminal || ddo.priority < self.priority)) { input.setAttribute(value, tAttrs[attr]); } if (attr !== 'class') { tElement.removeAttr(value); } }); return function(scope) { scope.show = false; } } }; });
      
      





もちろん、 tranclude



使用することもできますが、その場合は、要素をコンテナにラップするか、庭などのフェンスにする必要があります。




このディレクティブの優先順位は前のものよりも高いため、目でフィールドを作成し、エラー処理ディレクティブを適用するだけです。 一方、優先度はng-if



またはng-repeat



の優先度よりも低いため、この構造はすべて必要に応じて非表示、表示、または伝播され、ディレクティブは互いにフレンドになります。



ライブの例: plnkr.co/edit/BSVN7zZb0vNEAXo7iWhM?p=preview



All Articles