1. ホーム
  2. angular

angualrコマンド(II)

2022-02-18 14:52:37

AngularJSディレクティブ上級編 - ngModelControllerの説明

Angularのディレクティブをカスタマイズする際、ディレクティブ間の通信に使用するrequireという項目があります。簡単な例として、今2つのディレクティブを書く必要があり、リンク関数に重複するメソッドがたくさんある場合、繰り返しを避けるために(有名なDRYの原則)、3番目のディレクティブのコントローラに重複するメソッドを書き、他の2つの必須ディレクティブでこのコントローラフィールドとこのメソッドをrequireし、最後にリンク関数の第4引数でこれらの重複メソッドを参照すればいいのです。コードの構造は、おおよそ次のようになります。

var app = angular.modeule('myapp',[]);

app.directive('common',function(){
    return {
    ...
    controller: function($scope){
        this.method1 = function(){
        };
        this.method2 = function(){
        };
    },
    ...
    }
});

app.directive('d1',function(){
    return {
    ...
    require: '? ^common',
    link: function(scope,elem,attrs,common){
        scope.method1 = common.method1;
        ...
        },
    ...
    }
});

app.directive('d2',function(){
    return {
    ...
    require: '? ^common',
    link: function(scope,elem,attrs,common){
        scope.method1 = common.method1;
        ...
        },
    ...
    }
});


もちろん、上記の例はディレクティブにおけるコントローラの使い方のひとつに過ぎません。一般にコントローラフィールドを使う機会はあまり多くありませんが、AngularJSのディレクティブをうまく書こうと思えば、必ずマスターしておきたいポイントです。

明らかにコントローラの使い方には2種類あり、1つはカスタムコントローラをrequireするもので、これはプロパティやメソッドをすべてカスタムコントローラに書くので使い勝手が良い。もう1つはAngularJSの組み込みディレクティブをrequireするもので、ほとんどの場合、ngModelディレクティブがrequireされることになる。多くの場合、ngModel の組み込みメソッドやプロパティに慣れていないため、コードを読んだり書いたりするのに苦労することがあります。本日の目的は、ngModel の組み込みプロパティとメソッドを詳しく紹介することであり、この記事を熟読すれば、ディレクティブで巧みに ngModel を require できるようになると思います。

ng-model ディレクティブは Angular アプリケーションにおいてビューとデータを結びつける双方向バインディングマジックに不可欠な要素です。ngModelController は ng-model ディレクティブで定義されたコントローラーです。このコントローラーにはデータバインディング、バリデーション、CSS 更新、値のフォーマットとパースに関するサービスを含んでいます。DOM レンダリングや DOM イベントのリスニングには使用されません。DOM 関連のロジックは他のディレクティブに含め、それらのディレクティブに ngModelController のデータバインディング機能を試してもらう必要があります。

ここでは、HTML5 の contenteditable プロパティを使用したシンプルなエディタディレクティブを作成し、データバインディングのためにディレクティブ定義で ngModel を必須とした例を示しています。

<ブロッククオート

HTMLセクション

<form name="myForm">
 <div contenteditable
  name="myWidget" ng-model="userContent"
  strip-br="true"
  required>Change me!</div>
  <span ng-show="myForm.myWidget.$error.required">Required!</span>
 <hr>
 <textarea ng-model="userContent"></textarea>
</form>


コマンド定義部

directive('contentitable', function() { return { restrict: 'A', // 要素属性として require: '?ngModel', // ngModelController を取得する link: function(scope, element, attrs, ngModel) { if(!ngModel) return; // ng-model がない場合は何もしない。

    // Specify how the UI is updated
    ngModel.$render = function() {
      element.html(ngModel.$viewValue || '');
    };

    // listen to the change event to enable binding
    element.on('blur keyup change', function() {
      scope.$apply(read);
    });
    read(); // initialize

    // Write data to the model
    function read() {
      var html = element.html();
      // When we clear the div the browser will leave a

tag // If the strip-br attribute is formulated, then the
tag will be cleared if( attrs.stripBr && html == '
' ) { html = ''; } ngModel.$setViewValue(html); } } };

});

ngModelController メソッド

  • $render()を使用します。

は、ビューを更新する必要があるときに呼び出されます。ng-model を使用するディレクティブは、このメソッド自体を実装する必要があります。

  • $isEmpty(value)を指定します。

このメソッドは、入力値が空かどうかを判断するために使用されます。 
例えば、ngModelController を使用するディレクティブが入力値があるかどうかを判断する必要がある場合、このメソッドが使用されます。このメソッドは、値が undefined、''、null、または NaN であるかどうかを判断するために使用することができます。 
このメソッドは任意にオーバーライドすることができます。

  • $setValidity(validationErrorKey, isValid)を指定します。

このメソッドは、バリデーションの状態を変更し、変更されたバリデーション基準を制御するときにフォームに通知するために使用されます。 
このメソッドは、バリデータから呼び出される必要があります。たとえばパーサーや書式設定関数などです。

  • $setPristine()を使用します。

このメソッドは、コントロールを元の状態に設定するために使用されます。 
このメソッドは 'ng-dirty' クラスを削除して、コントロールを元の状態 ('ng-pristine' クラス) に戻します。

  • $cancelUpdate()を実行します。

このメソッドは、保留中のデバウンスイベントによって発生する、 あるいは入力入力ボックスが将来のイベントを待っているために、 $viewCalue が更新されないように更新をキャンセルし、 入力要素の値をリセットするために使われます。

ng-model-options ディレクティブを使用する入力ボックスがあり、それに対して debounced イベントまたは blur-like イベントを設定すると、入力ボックス内の値と ngModel の $viewValue プロパティがある一定期間同期しない状況に遭遇することがあります。 
この場合、debounced/future イベントが発生する前に ngModel の $modelValue を更新しようとすると、AngularJS のダーティチェックのメカニズムが実際にモデルが変更されたかどうかを判断しないため、困難にぶつかる可能性が高いです。 
入力ボックスのモデルを変更する前に、$cancelUpdate() メソッドを呼び出す必要があります。これは、入力フィールドが新しいモデルの値で更新され、保留中の操作がキャンセルされることを保証するため、重要であることを覚えておいてください。以下はその例です。

HTMLセクション

 <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
<p>With $cancelUpdate()</p>
<input name="myInput1" ng-model="myValue" ng-keydown="resetWithCancel($event)"><br/>
myValue: "{{ myValue }}"

<p>Without $cancelUpdate()</p>
<input name="myInput2" ng-model="myValue" ng-keydown="resetWithoutCancel($event)"><br/>
myValue: "{{ myValue }}"
  </form>
</div>  


JSセクション

angular.module('cancel-update-example', [])

.controller('CancelUpdateCtrl', function($scope) {
  $scope.resetWithCancel = function (e) {
if (e.keyCode == 27) {
  $scope.myForm.myInput1.$cancelUpdate();
  $scope.myValue = '';
}
  };
  $scope.resetWithoutCancel = function (e) {
if (e.keyCode == 27) {
  $scope.myValue = '';
}
  };
});  


  • $setViewValue(value, trigger) メソッド

    このメソッドは、ビューの値を更新するために使用されます。このメソッドは、ビューの値が変更されたとき、通常は DOM イベントハンドラ関数の中でコールされるべきものです。例えば、input ディレクティブや select ディレクティブはこの関数を呼び出します。 
    このメソッドは $viewValue プロパティを更新し、 この値をバリデータを含む $parsers 内の各関数に渡します。この値は$parsersから出力され、$modelValueとng-modelプロパティの式で使用されます。 
    最後に、$viewChangeListeners リストに登録されたすべてのリスナーが呼び出されます。

ngModelControllerのプロパティ

  • $viewValue

    ビューの実際の値

  • モデル値

    モデル内の値で、コントローラに金額でバインドされています。

  • $parsers

    コントローラが DOM から値を読み込むたびに実行される関数の配列で、パイプラインとして動作します。この中の関数が順番に呼び出され、その結果が次の関数に渡されます。最終的に出てきた値は、モデルに渡されます。これには、値の検証や変換の処理も含まれます。検証のステップでは、パーサーは $setValidity メソッドを使用し、不適格な値に対しては undefined を返します。

  • フォーマッター

    MODの値が変更されるたびに、次の関数を含む配列がパイプラインとして動作します。これらの関数は順番に呼び出され、その結果は次の関数に渡されます。この関数は、モデルからビューに渡される値をフォーマットするために使用されます。

    • $viewChangeListeners

ビューに含まれる関数は、ビューの値が変化するたびに実行されます。関数は引数なしで実行され、その戻り値は無視されます。追加の#watchで使用することができます。

  • エラー

すべてのエラーを含むオブジェクト

  • $pristine

ユーザーがまだ操作していない場合、この値はtrueになります。

  • $dirty

ユーザーがすでにインタラクションを行った場合、この値はtrueになります。

  • 有効

エラーがなければ、値はtrueです。

  • 無効

エラーが発生した場合、値はtrueになります。


この記事はAngularJSのドキュメントを参照しており、元々は以下のサイトで公開されたものです。 https://docs.angularjs.org/api/ng/type/ngModel.NgModelController