78

カスタム ディレクティブを新しいコンポーネント アーキテクチャにアップグレードしています。コンポーネントがウォッチャーをサポートしていないことを読みました。これは正しいです?もしそうなら、オブジェクトの変化をどのように検出しますか? myBox基本的な例として、ゲームにバインディングを持つ子コンポーネント game を持つカスタム コンポーネントがあります。ゲーム コンポーネント内に変更ゲームがある場合、myBox 内にアラート メッセージを表示するにはどうすればよいですか? rxJS メソッドがあることを理解していますが、これを純粋に角度で行うことは可能ですか? 私のJSFiddle

JavaScript

var app = angular.module('myApp', []);
app.controller('mainCtrl', function($scope) {

   $scope.name = "Tony Danza";

});

app.component("myBox",  {
      bindings: {},
      controller: function($element) {
        var myBox = this;
        myBox.game = 'World Of warcraft';
        //IF myBox.game changes, show alert message 'NAME CHANGE'
      },
      controllerAs: 'myBox',
      templateUrl: "/template",
      transclude: true
})
app.component("game",  {
      bindings: {game:'='},
      controller: function($element) {
        var game = this;


      },
      controllerAs: 'game',
      templateUrl: "/template2"
})

HTML

<div ng-app="myApp" ng-controller="mainCtrl">
  <script type="text/ng-template" id="/template">
    <div style='width:40%;border:2px solid black;background-color:yellow'>
      Your Favourite game is: {{myBox.game}}
      <game game='myBox.game'></game>
    </div>
  </script>

 <script type="text/ng-template" id="/template2">
    <div>
    </br>
        Change Game
      <textarea ng-model='game.game'></textarea>
    </div>
  </script>

  Hi {{name}}
  <my-box>

  </my-box>

</div><!--end app-->
4

7 に答える 7

159

ウォッチャーなしでコンポーネントを作成する

この回答では、ウォッチャーを使用せずに AngularJS 1.5 コンポーネントを作成するために使用する 5 つの手法について概説しています。


ng-changeディレクティブを使用する

AngularJs2 の準備として watch を使用せずに obj の状態の変化を観察するために使用できる代替メソッドは何ですか?

ng-changeディレクティブを使用して、入力の変更に対応できます。

<textarea ng-model='game.game' 
          ng-change="game.textChange(game.game)">
</textarea>

また、イベントを親コンポーネントに伝達するには、イベント ハンドラーを子コンポーネントの属性として追加する必要があります。

<game game='myBox.game' game-change='myBox.gameChange($value)'></game>

JS

app.component("game",  {
      bindings: {game:'=',
                 gameChange: '&'},
      controller: function() {
        var game = this;
        game.textChange = function (value) {
            game.gameChange({$value: value});
        });

      },
      controllerAs: 'game',
      templateUrl: "/template2"
});

そして、親コンポーネントで:

myBox.gameChange = function(newValue) {
    console.log(newValue);
});

これは、今後推奨される方法です。使用する AngularJS 戦略$watchは、ポーリング戦略であるため、スケーラブルではありません。リスナーの数が$watch2000 前後になると、UI が遅くなります。Angular 2 の戦略は、フレームワークをより反応的にし、配置を避けること$watchです$scope


$onChangesライフサイクル フックを使用する

バージョン 1.5.3で、AngularJS はサービスにライフサイクル フックを追加しまし$onChanges$compile

ドキュメントから:

コントローラーは、ライフサイクル フックとして機能する次のメソッドを提供できます。

  • $onChanges(changesObj) - 一方向 ( <) または補間 ( @) バインディングが更新されるたびに呼び出されます。はchangesObj、キーが変更されたバインドされたプロパティの名前であり、値が形式のオブジェクトであるハッシュです{ currentValue: ..., previousValue: ... }。このフックを使用して、バインドされた値のクローンを作成するなど、コンポーネント内の更新をトリガーして、外部値の偶発的な変更を防ぎます。

— AngularJS Comprehensive Directive API Reference -- ライフサイクル フック

フックは、一方向バインディング$onChangesでコンポーネントへの外部変更に対応するために使用されます。<このng-changeディレクティブは、コントローラーからの変更をバインディングを使用しng-modelてコンポーネントの外部に伝搬するために使用されます。&


$doCheckライフサイクル フックを使用する

バージョン 1.5.8で、AngularJS はサービスにライフサイクル フックを追加しまし$doCheck$compile

ドキュメントから:

コントローラーは、ライフサイクル フックとして機能する次のメソッドを提供できます。

  • $doCheck()- ダイジェスト サイクルの各ターンで呼び出されます。変化を検出して対応する機会を提供します。検出した変更に応じて実行するアクションはすべて、このフックから呼び出す必要があります。これを実装しても、いつ$onChanges呼び出されるかには影響しません。たとえば、このフックは、深い等価性チェックを実行したい場合や、Date オブジェクトをチェックしたい場合に役立ちます。これらの変更は、Angular の変更検出器によって検出されず、トリガーされません$onChanges。このフックは引数なしで呼び出されます。変更を検出した場合は、現在の値と比較するために以前の値を保存する必要があります。

— AngularJS Comprehensive Directive API Reference -- ライフサイクル フック


とのコンポーネント間通信require

ディレクティブは、相互の通信を可能にするために、他のディレクティブのコントローラーを要求できます。これは、 requireプロパティにオブジェクト マッピングを提供することにより、コンポーネントで実現できます。オブジェクト キーは、必要なコントローラー (オブジェクト値) が必要なコンポーネントのコントローラーにバインドされるプロパティ名を指定します。

app.component('myPane', {
  transclude: true,
  require: {
    tabsCtrl: '^myTabs'
  },
  bindings: {
    title: '@'
  },
  controller: function() {
    this.$onInit = function() {
      this.tabsCtrl.addPane(this);
      console.log(this);
    };
  },
  templateUrl: 'my-pane.html'
});

詳細については、AngularJS 開発者ガイド - コンポーネント間通信を参照してください。


RxJSを使用してサービスから値をプッシュする

たとえば、状態を保持している Service がある状況ではどうでしょう。そのサービスに変更をプッシュし、ページ上の他のランダムなコンポーネントがそのような変更を認識できるようにするにはどうすればよいですか? 最近、この問題に取り組むのに苦労しています

RxJS Extensions for Angularを使用してサービスを構築します。

<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);

app.factory("DataService", function(rx) {
  var subject = new rx.Subject(); 
  var data = "Initial";

  return {
      set: function set(d){
        data = d;
        subject.onNext(d);
      },
      get: function get() {
        return data;
      },
      subscribe: function (o) {
         return subject.subscribe(o);
      }
  };
});

次に、変更を購読するだけです。

app.controller('displayCtrl', function(DataService) {
  var $ctrl = this;

  $ctrl.data = DataService.get();
  var subscription = DataService.subscribe(function onNext(d) {
      $ctrl.data = d;
  });

  this.$onDestroy = function() {
      subscription.dispose();
  };
});

クライアントは で変更をサブスクライブできDataService.subscribe、プロデューサーは で変更をプッシュできますDataService.set

PLNKRのデモ。

于 2016-02-21T11:10:58.370 に答える
8

$watchオブジェクトはオブジェクト内で使用できる$scopeため、コントローラーのファクトリ関数内に追加してから$scope、ウォッチャーを変数に配置する必要があります。

$scope.$watch(function(){
    return myBox.game;
}, function(newVal){
   alert('Value changed to '+ newVal)
});

デモはこちら

注:の依存関係を削除して、Angular2 に一歩近づくためにに変換directiveしたことは知っています。しかし、この場合は削除されなかったようです。 component$scope

アップデート

基本的に、angular 1.5 は.component、2 つの異なる機能を区別するメソッドを追加しました。Like component.stands は を追加して特定の動作を実行することを表しselector、asdirectiveは特定の動作を DOM に追加することを表します。.directiveDirective は、 DDO(Directive Definition Object)の単なるラッパー メソッドです。あなたが見ることができるのは、angularコンパイルされたDOMを取得できるメソッドlink/compileを使用しているときに、関数を削除していたことだけです。.component

Angular コンポーネント ライフサイクル フックの$onChanges/ライフサイクル フックを使用してください。これらは Angular 1.5.3 以降のバージョンで利用可能になります。$doCheck

$onChanges(changesObj) - バインディングが更新されるたびに呼び出されます。changesObj は、キーがバインドされたプロパティの名前であるハッシュです。

$doCheck() - バインディングが変更されると、ダイジェスト サイクルの各ターンで呼び出されます。変化を検出して対応する機会を提供します。

コンポーネント内で同じ関数を使用することで、Angular 2 に移行するためのコードの互換性が確保されます。

于 2016-02-21T10:11:30.787 に答える
2

ng-change受け入れられた回答で推奨されているように、Angular 1.5コンポーネントとともにの使用に関する小さな注意事項。

ng-model動作しng-changeないコンポーネントを監視する必要がある場合は、パラメーターを次のように渡すことができます。

コンポーネントが使用されているマークアップ:

<my-component on-change="$ctrl.doSth()"
              field-value="$ctrl.valueToWatch">
</my-component>

コンポーネント js:

angular
  .module('myComponent')
  .component('myComponent', {
    bindings: {
      onChange: '&',
      fieldValue: '='
    }
  });

コンポーネントのマークアップ:

<select ng-model="$ctrl.fieldValue"
        ng-change="$ctrl.onChange()">
</select>
于 2016-10-03T15:23:57.230 に答える