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
}

Answers:


226

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

虽然我喜欢drewmoore的答案,并在其中看到了完美的概念逻辑,但在实现上却是错误的。模板不存在于组件类中,而是在它们之外。看看这个回购作为证明。

它起作用的唯一原因是因为TypeScript的private关键字并未真正使成员私有。即时编译在运行时在浏览器中进行,并且JS没有任何私有成员的概念(还可以吗?)。幸得桑德埃利亚斯为把我在正确的轨道上。

使用“ ngc和提前”编译,如果尝试从模板访问组件的私有成员,则会出现错误。克隆演示仓库,将MyComponent成员的可见性更改为private,运行时会遇到编译错误ngc。这也是提前编译的特定答案


6
这是最好的评论,imo应该是公认的答案。并不是一旦转译就可以使用私有变量,而是应该..保持代码干净!
山姆·弗洛伯格

2
这是唯一有效的答案!现在,当您在模板中使用private var时,Codelyzer会警告您。
maxime1992 '16

7
我唯一的问题是,如何区分实际公开的成员(例如@Inputs和成员的Outputs),而这些成员只希望公开给我们的模板而不是外界。如果要构建可重用的组件,则希望模板可以访问方法/成员,但其他组件不能访问。我认为原始答案是正确的。模板是组件的一部分。
Ashg

1
我同意@Ashg-不仅是wrt输入和输出。当我想组件之间进行通信时,例如将父组件注入其子组件,该怎么办?然后,子组件可以看到父组件要向其模板公开的所有内容,而不仅仅是父组件要向外界公开的方法。在Angular的限制内,此答案仍然是正确的答案,但我认为这种设计并未经过深思熟虑。
丹·金

这是一个很好的答案,因为它解决了Angular的AoT编译中的限制以及如何解决它们。但是,IMO的问题是概念性的(有意或无意)。从概念上讲,模板是类定义的一部分。模板既不扩展也不继承类,并且它们不从外部访问实例化的对象……反之亦然。模板是在类本身内定义的,因此,从概念上讲,它们是类的一部分,从概念上讲,应该可以访问私有成员。
A-Diddy

85

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


是的,这是预期的。

请记住,private和其他访问修饰符是Typescript构造,而Component / controller / template是Typescript一无所知的角度构造。访问修饰符控制可视性之间类:制作领域private防止其他类有机会接触到它,但模板和控制器是存在的事情的类。

从技术上讲,这不是正确的,但是(代替理解类与装饰器及其元数据的关系),以这种方式思考可能会有所帮助,因为重要的是(IMHO)不再将模板和控制器视为独立实体将其视为Component构造的统一部分-这是ng2心理模型的主要方面之一。

以这种方式考虑,显然,我们希望private组件类中的变量在其模板中可见,出于同样的原因,我们希望它们在private该类的方法中可见。


3
首先,我想就像你画画一样。但是我将tslint升级到4.02,将codelyzer升级到2.0.0-beta.1,并且出现错误,说我在访问视图变量时不能使用private。因此,@ Yaroslav的答案似乎更合适。
maxime1992 '16

8
我同意,对于组件模型来说,看不到其私有变量是没有意义的,它们可能应该在编译过程中混入同一类中,我的意思是,您必须将组件特定的特征,对象和函数公开给所有其他组件,以便您可以在模板中使用这些组件,更不用说外部调整或对这些组件的调用可能会在完成的组件上引起潜在的意外行为
Felype

1
@drewmoore,你好,我只编码角几个月了。我遇到了这个问题。关于此还有进一步的辩论吗?由于我没有找到关于遵循哪种模式的具体信息。imo值得一看,它似乎违反了代码分离。
Edgar

2
@drewmoore,我必须说我完全同意您的分析服务逻辑。恐怕Angular团队搞砸了。在AOT模式下,他们不允许私人成员,而在文档中则声明不这样,对于私人成员,这绝对是在加强您的观点,并且只会给该主题增加更多混乱。来自Docs:“ Angular将组件的模板视为属于该组件。该组件及其模板隐含地相互信任。因此,无论带或不带* @ * Input装饰器,组件自己的模板都可以绑定到该组件的任何属性。 ”
奥勒尔·埃拉基

@drewmoore,文档链接:angular.io/guide/attribute-directives#appendix-why-add-input(我知道它主要集中在Input装饰器上,但是他们在谈论的很多东西都与它)
Orel Eraki

16

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

Dart中模板无法引用组件类的私有变量,因为与TypeScript相比,Dart有效地防止了从外部访问私有成员。

我仍然支持@drewmoores建议,将组件及其模板作为一个单元来考虑。

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


2
是否可以使用Typescript编译器来限制视图可访问的私有变量?
马修·哈伍德

我不知道。我猜不会。
君特Zöchbauer

2
我认为将它们私有化会影响该组件的可测试性是否正确?例如,如果我在测试的上下文中创建组件,则无法从测试中调用那些私有方法来确认模板/类交互是否正常。我还没有尝试过,所以如果这很明显,请原谅我:)
Sam Storie

在Dart中,您无法访问测试中的私人成员。有很多讨论(与语言无关)是否应该支持它以及是否应该对私有API进行测试。测试公共API应该能够到达每个代码路径。我认为这总体上是合理的。在Dart中,每个库都是私有的(可以包含多个文件),这使得公共API相当广泛-IMHO对于单元测试而言太广泛了。
君特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),但没有发现任何暗示在模板中使用私有变量的地方。相反,他们使用getter和setter从模板访问私有变量。
塞巴斯蒂安·沙蒂尔

3

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

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

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


我认为,例如,为了保持一致性,如果您将_userName更改为_clientName,则需要更改getter以获得clientName…因此没有胜利
LeagueOfJava '18

用户对私有变量加下划线是一种不好的做法。
Florian Leitgeb,

1
@FlorianLeitgeb这就是为什么Angular官方文档会这么做的原因private _name = '';
鲁芬'18

然后,此代码段未正确检查。它们遵循样式约定,该约定在此处的样式指南中声明。并且在其页面上的Typescript类部分中,此处也不使用下划线。
Florian Leitgeb

1
@FlorianLeitgeb那么,如ruffin发布的链接中所示,对设置方法的拦截的建议解决方案是什么?即,您怎么称呼设置员的私人支持领域?
El Ronnoco '19

1

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


0

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

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

}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.