web-dev-qa-db-ja.com

Angular 1.5コンポーネント($ scope。$ watchなし)でバインドを待機する方法

私はAngular 1.5ディレクティブを書いていますが、バインドされたデータが存在する前に操作しようとすると厄介な問題にぶつかります。

ここに私のコードがあります:

app.component('formSelector', {
  bindings: {
    forms: '='
  },
  controller: function(FormSvc) {

    var ctrl = this
    this.favorites = []

    FormSvc.GetFavorites()
    .then(function(results) {
    ctrl.favorites = results
    for (var i = 0; i < ctrl.favorites.length; i++) {
      for (var j = 0; j < ctrl.forms.length; j++) {
          if (ctrl.favorites[i].id == ctrl.newForms[j].id) ctrl.forms[j].favorite = true
      }
     }
    })
}
...

ご覧のとおり、AJAXを呼び出してお気に入りを取得し、フォームのバインドされたリストと照合します。

問題は、バインディングが読み込まれる前でも約束が満たされていることです...そのため、ループを実行するまでにctrl.formsは未定義です!

$ scope。$ watch(1.5コンポーネントの魅力の一部)を使用せずに、バインディングが完了するまでどのように待ちますか?

35
tcmoore

新しいライフサイクルフック、特に $onChangesisFirstChangeメソッドを呼び出してバインディングの最初の変更を検出します。詳細についてはこちらをご覧ください こちら

以下に例を示します。

<div ng-app="app" ng-controller="MyCtrl as $ctrl">
  <my-component binding="$ctrl.binding"></my-component>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js"></script>
<script>
  angular
    .module('app', [])
    .controller('MyCtrl', function($timeout) {
      $timeout(() => {
        this.binding = 'first value';
      }, 750);

      $timeout(() => {
        this.binding = 'second value';
      }, 1500);
    })
    .component('myComponent', {
      bindings: {
        binding: '<'
      },
      controller: function() {
        // Use es6 destructuring to extract exactly what we need
        this.$onChanges = function({binding}) {
          if (angular.isDefined(binding)) {
            console.log({
              currentValue: binding.currentValue, 
              isFirstChange: binding.isFirstChange()
            });
          }
        }
      }
    });
</script>
27
Cosmin Ababei

同様の問題がありました。送信する値の準備ができるまでコンポーネントの呼び出しを回避するためにこれを行いました。

<form-selector ng-if="asyncValue" forms="asyncValue" ></form-selector>
34
Ced

元のポスターは言った:

バインディングが読み込まれる前でも約束は満たされています...ループを実行する頃には、ctrl.formsは未定義のままです

AngularJS 1.5.3以降、 ライフサイクルフック があり、OPの質問を満たすには、$onInit()内で満たされているバインディングに依存するコードを移動するだけです。

$ onInit()-要素のすべてのコントローラーが構築され、バインディングが初期化された後(およびこの要素のディレクティブのリンク機能の前後に)各コントローラーで呼び出されます。これは、コントローラーの初期化コードを置くのに適した場所です。

したがって、例では:

app.component('formSelector', {
  bindings: {
    forms: '='
  },
  controller: function(FormSvc) {
    var ctrl = this;
    this.favorites = [];

    this.$onInit = function() {
      // At this point, bindings have been resolved.
      FormSvc
          .GetFavorites()
          .then(function(results) {
            ctrl.favorites = results;
            for (var i = 0; i < ctrl.favorites.length; i++) {
              for (var j = 0; j < ctrl.forms.length; j++) {
                if (ctrl.favorites[i].id == ctrl.newForms[j].id) {
                  ctrl.forms[j].favorite = true;
                }
              }
            }
          });
    }
}

そのため、$onChanges(changesObj)がありますが、$onInit()は、バインディングが解決されたという保証をいつ取得できるかという元の質問に具体的に対処します。

7
Oli

同様の問題がありましたが、この記事は非常に役に立ちました。 http://blog.thoughtram.io/angularjs/2016/03/29/exploring-angular-1.5-lifecycle-hooks.html

ページのロード時にサーバーにヒットするajax呼び出しがあり、コンポーネントを正しくロードするにはajaxの戻り値が必要です。この方法で実装しました:

this.$onChanges = function (newObj) {
      if (newObj.returnValFromAJAX)
        this.returnValFromAJAX = newObj.returnValFromAJAX;
    };

これで、私のコンポーネントは完全に機能します。参考のために、Angular 1.5.6

1
tperdue321