web-dev-qa-db-ja.com

コンポーネントバインディングがコントローラーで未定義なのはなぜですか?

単純なangularコンポーネントを書いています。パラメーターをバインディングとして渡し、その値を画面に表示しています。すべて正常に動作します。画面に表示されているパラメーターを確認できます。

成分:

var app = angular.module("test", []);
app.component("test", {
  bindings: {
    "contactId": "<"
  },
  controllerAs: "model",
  controller: () => {
    //output: 'contact id from controller: undefined'
    console.log(`contact id from controller: ${this.contactId}`);
  },
  template: "<div>Contact id from view: {{model.contactId}}</div>"
});

HTML:

<test contact-id="8"></test>

ただし、コントローラー内からバインディングにアクセスしようとすると(console.logを参照)、バインディング値はundefinedです。ビューでどのように使用できるかわかりませんが、コントローラーではわかりません。

私は何を間違えていますか?

plnkr が問題を示しています。

58
fikkatra

アンギュラーのコンポーネントを使用する場合、コントローラーが内部linkingを介して接続されていないポイントがあります。コントローラーのコンストラクターでこれを行おうとしている場合、バインディングにリンクされていません。コンポーネントAPIは、特定の時間に起動する、定義可能ないくつかのライフサイクルフックを公開します。 $onInitフックを探しています。

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

ドキュメントごと- https://docs.angularjs.org/guide/component

54
jusopi

HTMLのバインディングにはhyphensを使用し、JavascriptのバインディングにはcamelCaseを使用してください。

app.component("test", {
  bindings: {
    "myContactId": "<"
  }
}

<test my-contact-id="8"></test>

それは私がいつもやることを忘れていることです。

25
kolobok

contactIdの値は、コントローラーの$scopeで利用できます。

var app = angular.module("test", []);
app.component("test", {
  bindings: {
    "contactId": "<"
  },
  controllerAs: "model",
  controller: ($scope) => {
    var model = $scope.model;
    alert(`contact id from controller: ${model.contactId}`);
  },
  template: "<div>Contact id from view: {{model.contactId}}</div>"
});

Plunkerの別のバージョンへのリンク ここ

7
JohnnyCoder

キーワードthisは矢印関数では機能しないようです。これは

controller: function() {
   alert('contact id from controller: ' + this.contactId);
}

矢印関数thisを使用する場合、ウィンドウオブジェクトを参照しているようです。

矢印関数は、独自のこのコンテキストを作成するのではなく、囲むコンテキストのthis値をキャプチャします

6
Olivier Boissé

これらの異常なバグを避けるために本当に必要ないくつかの変更を提案します。

app.component("test", {
  bindings: {
    "myContactId": "<"
  },
  controller:function(){
   var self=this;
   this.$onInit=function(){
    // do all your initializations here.
    // create a local scope object for this component only. always update that scope with bindings. and use that in views also.

       self.myScopeObject=self.myContactId
   }
  },
   template:'<p>{{$ctrl.myScopeObject}}</p>'
 }

<test my-contact-id="8"></test>

いくつかのポイント:

  1. htmlのコンポーネントにバインディングを渡すことは、常にmy-contact-idのケバブケースに入れられ、そのそれぞれのjavascript変数はcammalケース:myContactIdになります。

  2. オブジェクトのinsted値を渡す場合は、バインディングで「@」を使用します。オブジェクトを使用し、オブジェクトをbindigsに渡す場合は、 '<を使用します。そのオブジェクトへの双方向バインディングが必要な場合は、バインディング構成で「=」を使用します

 bindings:{
      value:'@',
      object:'<', // also known as one-way
      twoWay:'='
    }
4
hannad rehman

ベストプラクティスではないかもしれませんが、これらの値に簡単にアクセスできます。

$scope.$ctrl.contactId

$ scope内の$ ctrlプロパティですべてのバインディングを取得できます。

私はその助けを願っています

1
BratisLatas

私の問題に遭遇する可能性のある人のために、@ jusopiと受け入れられた回答のフォローアップとして、別の回答を追加します。コンポーネントに関しては、$onInitフックの後でも、サーバーからの値がまだ受信されていないため、データはnullのままでした。これに対抗するために(この状況を処理するより良い方法があるかもしれませんが)、$onChangesフックも活用しました。 $onChangesは、渡されたときに変更されたデータを返します。その情報を解析するか、単にバインディングをthis.contactIdとして呼び出すと、更新されます。

詳細は ドキュメント で提供されています: https://docs.angularjs.org/guide/component

0
CoolestNerdIII

「未定義」エラーの原因となるコードには2つの問題があります。

  1. 上記のように、最初に$ onInitライフサイクルフックに到達する必要があります。すべてのバインディングが作成されると、onInitが起動されます。

公式ドキュメントから: AngularJs Documentation

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

  1. 2つ目の問題は、コントローラー関数のパラメーターとして「()=>」矢印表記を使用すると、コントローラーがライフサイクルフックに到達しないことです。

問題は、矢印表記が独自のスコープを持たず、それを囲むスコープを使用することです。つまり、「this」を使用する場合、コンポーネントではなくウィンドウオブジェクトを参照します。したがって、this。$ onInit()を呼び出すと、ウィンドウ上で呼び出され、ウィンドウ上に存在しないため、起動されません。

0
Sotem

コンポーネントが想定されているディレクティブを使用している場合、bindings {}が指定されている場合、それらと同じパラメーターをscope {}に追加すると表示されます:

/*bindings: {
    modalInstance: '<',
    resolve: '<'
},*/
scope: {
    modalInstance: '<',
    resolve: '<'
},

*上記を書いた後、$ scope.resolveから割り当てるまで、追加のスコープパラメーターfooが$ scopeで使用できないことを発見しました。そのため、$ scope.init()でこれを行わなければなりませんでした:$ scope.foo = $ scope.resolve.foo。理由はわかりません。 UI Bootstrap Modal + Directivesの使用に関係していると思います

これは他の人には明らかかもしれませんが、私にとってはAnguluarJSに比較的慣れていませんでした。

私の問題は、ディレクティブと互換性があるが、コンポーネントで使用するために設計および文書化されたUIブートストラップモーダルでディレクティブを使用することでした。

0
Shovas