Angular2 - should private variables be accessible in the template?

TypescriptAngularAngular2 Template

Typescript Problem Overview


If a variable is declared private on a component class, should I be able to access it in the template of that component?

@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
}

Typescript Solutions


Solution 1 - Typescript

No, you shouldn't be using private variables in your templates.

While I like the drewmoore's answer 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 for the proof.

The only reason why it works is because TypeScript's private keyword doesn't really make member private. Just-in-Time compilation happens in a browser at runtime and JS doesn't have any concept of private members (yet?). Credit goes to Sander Elias for putting me on the right track.

With ngc and Ahead-of-Time compilation, you'll get errors if you try accessing private members of the component from template. Clone demonstration repo, change MyComponent members' visibility to private and you will get compilation errors, when running ngc. Here is also answer specific for Ahead-of-Time compilation.

Solution 2 - Typescript

Edit: This answer is now incorrect. There was no official guidance on the topic when I posted it, but as explained in @Yaroslov's (excellent, and correct) answer, this is no longer the case: Codelizer now warns and AoT compilation will fail on references to private variables in component templates. That said, on a conceptual level everything here remains valid, so I'll leave this answer up as it seems to have been helpful.


Yes, this is expected.

Keep in mind that private and other access modifiers are Typescript constructs, whereas Component/controller/template are angular constructs that Typescript knows nothing about. Access modifiers control visibility between classes: Making a field private prevents other classes from having access to it, but templates and controllers are things that exist within classes.

That's not technically true, but (in lieu of understanding how classes relate to decorators and their metadata), it might be helpful to think of it this way, because the important thing (IMHO) is to shift from thinking about template and controller as separate entities into thinking of them as unified parts of the Component construct - this is one of the major aspects of the ng2 mental model.

Thinking about it that way, obviously we expect private variables on a component class to be visible in its template, for the same reason we expect them to be visible in the private methods on that class.

Solution 3 - Typescript

Even though the code example indicates the question is about TypeScript it doesn't have the [tag:typescript] tag. Angular2 is also available for Dart and this is a notable difference to Dart.

In Dart the template can't reference private variables of the component class, because Dart in contrast to TypeScript effectively prevents access of private members from outside.

I still back @drewmoores suggestion to think about component and it's template as one unit though.

Update (TS) It seems with offline compilation access to private properties will become more limited in Angular2 TS as well https://github.com/angular/angular/issues/11422

Solution 4 - Typescript

A workaround could be using private variables in ts file and using getters.

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

This is a good approach because the ts file and the html remains independent. Even if you change the _userName variable name in ts file, you dont have to make any change in the template file.

Solution 5 - Typescript

Private variables can be using within the template of component. See angular2 cheat-sheet for guide: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

A more detailed explanation on public/private members of classes in typescript can be found here: https://www.typescriptlang.org/docs/handbook/classes.html.

All members by default are Public. Public members can be accessed from outside the component class along with the class-instance. But Private members can be accessed only within the class member functions.

Solution 6 - Typescript

The short answer is no you should not be able to access private members from the template because it is technically separated from the TS file.

Solution 7 - Typescript

In tsconfig.app.json if you provide the 'fullTemplateTypeCheck' option in compiler options you can see all the invalid references in html files of your project at the time of project build.

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

}

Solution 8 - Typescript

I know that this is a little late, but I've been preocuppied with this problem even since Angular2 and finally I've come up with a nice workaround to allow me to have nice proper components API's and also to be able to access private fields in them from templates with proper type checking:

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

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

In this way, as you can see, we will have even type checking and all we need in the html template and also a proper API of the component. If in another component we reference the MyComponent class like this:

export class OtherComponent {
    private _m: MyComponent;

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

we will notice the property _label is not visible.

Of course, notice that the class MyComponent should not implement the interface MyComponentPrivateProperties. There will be no implementation for this interface. This is just a description for the angular ngc compiler. It tells the compiler at compile time which are the private properties that should be accessible from the templates and then dissapears at run time.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question3gwebtrainView Question on Stackoverflow
Solution 1 - TypescriptYaroslav AdminView Answer on Stackoverflow
Solution 2 - Typescriptdrew mooreView Answer on Stackoverflow
Solution 3 - TypescriptGünter ZöchbauerView Answer on Stackoverflow
Solution 4 - TypescriptFranklin PiousView Answer on Stackoverflow
Solution 5 - TypescriptanusreemnView Answer on Stackoverflow
Solution 6 - TypescriptIvens ApplyrsView Answer on Stackoverflow
Solution 7 - TypescriptKhushbu SuryavanshiView Answer on Stackoverflow
Solution 8 - TypescriptCosmin PopescuView Answer on Stackoverflow