Angular2 - 私有变量是否可以在模板中访问?

Angular2 - should private variables be accessible in the template?

如果在组件 class 上声明了一个变量 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
}

编辑:这个答案现在不正确了。 我发布这个主题时没有官方指导,但正如@Yaroslov(优秀且正确)的答案中所解释的那样,情况不再如此:Codelizer 现在会发出警告,并且 AoT 编译将在引用组件模板中的私有变量时失败。也就是说,在概念层面上,这里的所有内容仍然有效,所以我会保留这个答案,因为它似乎很有帮助。


是的,这是预期的。

请记住,private 和其他访问修饰符是 Typescript 构造,而 Component/controller/template 是 Typescript 一无所知的 angular 构造。访问修饰符控制可见性 between classes:使字段 private 防止 other classes 具有访问它,但模板和控制器是 within classes.

中存在的东西

这在技术上是不正确的,但是(代替理解 classes 如何与装饰器及其元数据相关),这样想可能会有所帮助,因为重要的是(恕我直言)从将模板和控制器视为独立的实体转变为将它们视为组件构造的统一部分——这是 ng2 心智模型的主要方面之一。

这样想,显然我们希望组件 class 上的 private 变量在其模板中可见,出于同样的原因,我们希望它们在 [=10] 中可见=] 方法 class。

尽管代码示例表明问题是关于 TypeScript 的,但它没有 标签。 Angular2 也可用于 Dart,这是与 Dart 的显着差异。

Dart 中,模板不能引用组件 class 的私有变量,因为 Dart 与 TypeScript 不同有效防止私有成员从外部访问。

不过,我仍然支持@drewmoores 将组件及其模板视为一个单元的建议。

更新 (TS) 似乎对于私有属性的离线编译访问在 Angular2 TS 中也会变得更加受限 https://github.com/angular/angular/issues/11422

UPD

从Angular14开始,在模板中绑定protected个组件成员是possible。这应该部分解决将内部状态(应该只能由模板访问)暴露为组件的 public API.

的问题

不,您不应该在模板中使用私有变量。

虽然我喜欢 and see perfect conceptual logic in it, implementationwise it's wrong. Templates do not exist within component classes, but outside of them. Take a look at this repo 作为证据。

它起作用的唯一原因是因为 TypeScript 的 private 关键字并没有真正使成员私有。即时编译发生在运行时的浏览器中,而 JS 没有任何私有成员的概念(还没有?)。感谢 Sander Elias 让我走上了正确的轨道。

使用 ngc 和提前编译,如果您尝试从模板访问组件的私有成员,您将遇到错误。克隆演示 repo,将 MyComponent 成员的可见性更改为私有,当 运行 ngc 时,你将得到编译错误。这里也是 特定于提前编译。

私有变量可以在组件模板中使用。请参阅 angular2 cheat-sheet 以获取指南:https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

有关打字稿中 classes 的 public/private 成员的更详细解释可在此处找到:https://www.typescriptlang.org/docs/handbook/classes.html.

所有成员默认为Public。 Public 成员可以从组件 class 外部与 class 实例一起访问。但是私有成员只能在 class 成员函数中访问。

解决方法是在 ts 文件中使用私有变量并使用 getter。

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

这是一个很好的方法,因为 ts 文件和 html 保持独立。即使你在ts文件中更改了_userName变量名,你也不必在模板文件中做任何更改。

简短的回答是不,您不应该能够从模板访问私有成员,因为它在技术上与 TS 文件分开。

在 tsconfig.app.json 中,如果您在编译器选项中提供 'fullTemplateTypeCheck' 选项,您可以在项目构建时看到项目的 html 文件中的所有无效引用。

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

}

我知道这有点晚了,但是从 Angular2 开始我就一直在关注这个问题,最后我想出了一个很好的解决方法来让我拥有合适的组件 API的并且还能够通过适当的类型检查从模板访问其中的私有字段:

export interface MyComponentPrivateProperties {
    _label: string;
}
export class MyComponent {
    private _label: string = 'Label';

    public get view(): MyComponentPrivateProperties {
        return this as any;
    }
}
<div>{{view._label}}</div>

通过这种方式,正如您所看到的,我们甚至可以在 html 模板中进行类型检查和我们需要的所有内容,还有一个适当的 API 组件。如果在另一个组件中我们像这样引用 MyComponent class:

export class OtherComponent {
    private _m: MyComponent;

    ngOnInit() {
        // here, this._label is not visible.
    }
}

我们会注意到 属性 _label 不可见。

当然,请注意 class MyComponent 不应实现接口 MyComponentPrivateProperties。该接口将没有实现。这只是 angular ngc 编译器的描述。它在编译时告诉编译器哪些私有属性应该可以从模板访问,然后在 运行 时间消失。