Angular2-テンプレートでプライベート変数にアクセスできる必要がありますか?


143

変数がprivateコンポーネントクラスで宣言されている場合、そのコンポーネントのテンプレートで変数にアクセスできますか?

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>{{title}}</h2>
      <h2>Hello {{userName}}</h2> // I am getting this name
    </div>
  `,
})
export class App {
  public title = 'Angular 2';
  private userName = "Test Name"; //declared as private
}

回答:


226

いいえ、テンプレートでプライベート変数を使用するべきではありません。

私はドリュームーアの答えを気に入っており、その中に完璧な概念的ロジックが見られますが、実装に関しては間違っています。テンプレートはコンポーネントクラス内には存在せず、それらの外部に存在します。このレポを見てください証明のためを。

これが機能する唯一の理由は、TypeScriptのprivateキーワードは実際にはメンバーを非公開にしないためです。ジャストインタイムのコンパイルは実行時にブラウザーで行われ、JSにはプライベートメンバーの概念が(まだ?)ありません。クレジットは私を正しい軌道に乗せたサンダーエリアスに行きます。

ngcし、事前コンパイラは、テンプレートからコンポーネントのプライベートメンバーにアクセスしようとした場合、あなたはエラーを取得します。デモンストレーションリポジトリのクローンを作成し、MyComponentメンバーの可視性をプライベートに変更すると、実行時にコンパイルエラーが発生しますngc。また、Ahead-of-Timeコンパイルに固有の回答もあります


6
これが最良のコメントであり、imoが受け入れられる答えになるはずです。トランスパイルされた後でプライベート変数を使用できるというわけではありません。コードをクリーンに保ってください。
Sam Vloeberghs 16

2
これが唯一の有効な答えです!テンプレートでプライベート変数を使用すると、Codelyzerが警告するようになりました。
maxime1992

7
これに関する私の唯一の問題は、@ InputsやOutputsなどの実際に公開されているメンバーを、外部の世界ではなくテンプレートだけに公開したいメンバーにどのように区別するかです。テンプレートにアクセスできるが他のコンポーネントにはアクセスできないメソッド/メンバーが必要な再利用可能なコンポーネントを構築する場合。元の答えは正しいと思います。テンプレートはコンポーネントの一部です。
Ashg

1
@Ashgに同意します。入力と出力だけではありません。たとえば、親コンポーネントを子に挿入するなどして、コンポーネント間で通信したい場合はどうでしょうか。子コンポーネントは、親が外の世界に公開したいメソッドだけでなく、親がテンプレートに公開しているすべてのものを見ることができます。Angularの制約の範囲内で、この答えは依然として正しいものですが、この設計が十分に検討されてきたとは思いません。
Dan King

これは、AngularのAoTコンパイル内の制限とそれらを回避する方法に対処するため、良い答えです。ただし、IMOの質問は概念的なものでした(意図的かどうかは関係ありません)。概念的には、テンプレートはクラス定義の一部です。テンプレートはクラスを拡張したり継承したりせず、インスタンス化されたオブジェクトに外部からアクセスすることもありません...逆です。テンプレートはクラス自体の中で定義されるため、概念的にはテンプレートはクラスの一部であり、概念的にはプライベートメンバーにアクセスできる必要があります。
A-Diddy

85

編集:この回答は正しくありません。私が投稿したときのトピックに関する公式のガイダンスはありませんでしたが、@ Yaroslovの(優れた、正しい)回答で説明されているように、これは当てはまりません:Codelizerが警告し、コンポーネントテンプレートのプライベート変数への参照でAoTコンパイルが失敗します。とは言っても、概念的なレベルでは、ここにあるすべてのものは有効なままなので、この回答は役に立ったと思われるのでそのままにしておきます。


はい、そうです。

privateと他のアクセス修飾子はTypescript構成体ですが、Component / controller / templateはTypescriptが何も知らない角度構成体であることを覚えておいてください。アクセス修飾子は間の可視性制御しますクラスます。フィールドprivateを作成すると、他のクラスがそのフィールドにアクセスできなくなりますが、テンプレートとコントローラーはクラス内に存在するものです。

それは技術的には真実ではありませんが、(クラスがデコレータとそのメタデータにどのように関連するかを理解する代わりに)このように考えると役立つかもしれません。重要なこと(IMHO)はテンプレートとコントローラを別々のものとして考えることからシフトすることですエンティティをそれらをコンポーネント構成の統合された部分として考えるようにします。これは、ng2メンタルモデルの主要な側面の1つです。

そのように考えるprivateと、コンポーネントクラスの変数がそのテンプレートに表示されることを期待しています。同じ理由で、privateそのクラスのメソッドに変数が表示されることを期待しています。


3
まず、私はあなたがドムーアを描いたように思いました。しかし、tslintを4.02に、codelyzerを2.0.0-beta.1にアップグレードすると、ビュー内の変数にアクセスするときにプライベートを使用できないというエラーが発生しました。したがって、@ Yaroslavの回答の方が適切と思われます。
maxime1992

8
コンポーネントモデルがプライベート変数を表示できないことは意味がないことに同意します。コンパイル中にそれらをおそらく同じクラスにマッシュする必要があります。つまり、コンポーネント固有の特性、オブジェクト、および関数を公開する必要があります。テンプレートでそれらを使用できるように、他のすべてのコンポーネント。外部の微調整やそれらの呼び出しは言うまでもなく、完成したコンポーネントで予期しない動作が発生する可能性があります
Felype

1
@drewmoore、こんにちは私は数ヶ月だけ角張ってコーディングしてきました。私はこの問題に直面しました。これについてさらに議論はありますか?私が従うべきパターンについて何も特定されていないので。imo、それが何か価値があるので、それはコード分離に違反しているようです。
エドガー

2
@drewmoore、私はあなたのanserロジックに完全に同意していると言わなければなりません。そして、Angularチームは少し混乱しています。AOTモードでは、プライベートメンバーを許可していませんが、ドキュメントではそうではないと主張していますが、プライベートメンバーの場合は、あなたのポイントを絶対的に強化し、このトピックにカオスを追加するだけです。ドキュメントから:「Angularはコンポーネントのテンプレートをコンポーネントに属するものとして扱います。コンポーネントとそのテンプレートは互いに暗黙的に信頼します。したがって、コンポーネントの独自のテンプレートは、* @ * Inputデコレータの有無にかかわらず、そのコンポーネントの任意のプロパティにバインドできます。 」
Orel Eraki 2018

@drewmoore、ドキュメントのリンク:angular.io/guide/attribute-directives#appendix-why-add-input(私はそれが主に入力デコレータに焦点を当てていることを知っていますが、彼らが話していることの多くは単に関連しているわけではありませんit)
Orel Eraki 2018

16

コード例では質問がTypeScriptに関するものであることを示していますが、 鬼ごっこ。Angular2はDartでも利用でき、これはDartとの大きな違いです。

ダートテンプレートはプライベート変数を参照できませんダートが活字体とは対照的に、効果的に外部からのプライベートメンバーのアクセスを防止するため、コンポーネントクラスのを。

ただし、@ drewmooresの提案に戻って、コンポーネントとテンプレートを1つの単位として考えることを考えます。

更新(TS) プライベートプロパティへのオフラインコンパイルアクセスでは、Angular2 TSでもより制限されるようですhttps://github.com/angular/angular/issues/11422


2
Typescriptコンパイラを使用して、ビューにアクセスできるプライベート変数を制限することはできますか?
マシューハーウッド、2016年

知りません。私はそうは思いません。
ギュンターZöchbauer

2
それらをプライベートにすると、コンポーネントがどれほどテスト可能であるかに影響を与える可能性があると思いますか?たとえば、テストのコンテキストでコンポーネントを作成した場合、テストからこれらのプライベートメソッドを呼び出して、テンプレート/クラスの相互作用が機能していることを確認することはできません。私はまだこれを試していませんので、これが明らかな場合はご容赦ください:)
Sam Storie

Dartでは、テストでプライベートメンバーにアクセスできません。これをサポートする必要があるかどうか、およびプライベートAPIをまったくテストする必要があるかどうか(言語に依存しない)については多くの議論があります。パブリックAPIをテストすると、各コードパスに到達できるはずです。これは一般的に合理的だと思います。Dartでは、privateはライブラリ(複数のファイルで構成される場合があります)ごとにあり、これによりパブリックAPIがかなり広くなります。
ギュンターZöchbauer

3

コンポーネントのテンプレート内でプライベート変数を使用できます。ガイドについては、angular2チートシートを参照してください:https ://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

typescriptのクラスのパブリック/プライベートメンバーに関する詳細な説明は、https//www.typescriptlang.org/docs/handbook/classes.htmlにあります

デフォルトでは、すべてのメンバーがパブリックです。パブリックメンバーには、クラスインスタンスと共にコンポーネントクラスの外部からアクセスできます。ただし、プライベートメンバーには、クラスメンバー関数内でのみアクセスできます。


最初のリンク(angular.io/guide/component-interaction#!#parent-to-child-setter)を確認しましたが、テンプレートでプライベート変数を使用しても問題ないという箇所はありません。反対に、ゲッターとセッターを使用して、テンプレートからプライベート変数にアクセスします。
セバスチャンシャルティエ

3

回避策は、tsファイルでプライベート変数を使用し、ゲッターを使用することです。

private _userName = "Test Name";
get userName() {
  return this._userName;
}

tsファイルとhtmlは独立したままなので、これは良い方法です。tsファイルで_userName変数名を変更した場合でも、テンプレートファイルを変更する必要はありません。


たとえば、一貫性を保つために_userNameを_clientNameに変更した場合、clientNameを取得するためにゲッターを変更する必要があると思います...したがって、勝利はありません
LeagueOfJava

プライベート変数に対してアンダースコアを使用することは悪い習慣です。
Florian Leitgeb 2018年

1
@FlorianLeitgeb 公式のAngularドキュメントがそれを行う理由は何ですか?private _name = '';
ruffin

その後、このコードスニペットは適切にレビューされませんでした。これらは、ここのスタイルガイド宣言されているスタイル規則に従います。また、このページのTypescriptクラスセクションは、アンダースコアを使用していません。
Florian Leitgeb

1
@FlorianLeitgebでは、ruffinによって投稿されたリンクに示されているように、セッターメソッドのインターセプトに対して提案された解決策は何でしょうか。つまり、セッターのプライベートバッキングフィールドとは何ですか。
El Ronnoco

1

簡単に言えば、TSファイルから技術的に分離されているため、テンプレートからプライベートメンバーにアクセスすることはできません。


0

tsconfig.app.jsonでは、コンパイラオプションで「fullTemplateTypeCheck」オプションを指定すると、プロジェクトのビルド時にプロジェクトのhtmlファイル内の無効な参照がすべて表示されます。

"angularCompilerOptions": {
"enableIvy": true,
"fullTemplateTypeCheck": true

}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.