1

As far I can read the documentation there's only public and private as scopes in TypeScript. However, when I attempt the following exercise, I get different results, as if the variable environment isn't visible to the markup unless declared (publicly or privately).

<div class="text-section">
  Name is: {{environment.shazoo}}.
</div>
import { environment } from "../../../../environments/environment";
...
@Component({ ... })
export class DemoComponent implements OnInit {
  constructor(private builder: FormBuilder) { ... }
  ...
  private environment = environment;
}

The above example results in the text hazaa being displayed. However, if I comment out the line assigning the imported environment instance to the locally declared one, the text vanishes.

import { environment } from "../../../../environments/environment";
...
@Component({ ... })
export class DemoComponent implements OnInit {
  constructor(private builder: FormBuilder) { ... }
  ...
  // private environment = environment;
}

The way I figure, if the imported instance is visible in the code but not in the markup, there's a third level of scoping, whatever that might be (some kind of secludedly private thingy). But I hardly think that it's the case in reality. What am I missing?

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • Angular is weird about this - private variables usually aren't available in the templates of their own components but some compilers allows it - https://stackoverflow.com/questions/34574167/angular2-should-private-variables-be-accessible-in-the-template AOT compilation fails when doing it, but I just tested on plunkr and plunkr can reference private variables from templates just fine – diopside Aug 26 '17 at 13:38
  • So I think in many cases, even your first example won't be successful. But in general, the template has to have something in the component to give it context for any variable. It's not really aware of any typescript statements outside of its own class (component). – diopside Aug 26 '17 at 13:40
  • The transpile class version is just a function without private access modifiers => plain javascript. In your view Template, you can bind this field and use it. – theforce Aug 26 '17 at 14:35

1 Answers1

3

It seems that you're confusing TypeScript visibility with JavaScript contexts and variable scopes.

private and public are access modifiers and affect only type checking at compilation stage and are optional (except the case when they are used as constructor, where they are also implicitly assign a parameter as class property).

The meaning behind private environment = ... is that this.environment = ... happens in constructor under the hood. You can check in transpiled code that

export class DemoComponent implements OnInit {
  ...
  environment = environment;
}

results in this.environment = environment (public access modifier is optional here).

it's not possible to use imported environment variable (which is local to component module where it was imported ) in another place (compiled template), unless it was made available to the place where it should be used (template compiler), e.g. by assigning it to something it has access to (class property). This is suggested by the way how JavaScript works and isn't specific to Angular or TypeScript.

{{environment}} really means that environment property is being read from component class instance. Since template syntax is DSL that is defined by Angular compiler, this is available there but was made optional for brevity:

{{environment === this.environment}} is true

Finally, all component properties that are used in templates should be public, i.e. should not have private or protected access modifier. This is required for Angular AoT compilation.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • What led me to raised eyebrows is the fact that when I **don't** have the variable `private environment` declared (although I do have the importing statement), I get can assign values in my methods from it (i.e. `foo(){let x = environment.poof;}` works). What's up with that?! It seems that only the access in the template is blocked. – Konrad Viltersten Aug 26 '17 at 14:33
  • And a second follow-up - it seems that when I serve my code (i.e. *ng serve*), I get everything to work **but** as soon as I build it (i.e. *ng build*), the transpiler whines about the privacy forcing me to redeclare all the fields used in the template publicly. It's the difference between those two that makes me feel uneasy. – Konrad Viltersten Aug 26 '17 at 14:36
  • `environment` is *local variable*. You're referring to it as a variable, not as class property (`this.environment`). You have access to it inside component class because it was imported in the scope of the module where a class is defned. Re: `ng build`, this is exactly what the last paragraph about AoT refers to. Use public fields for template props. – Estus Flask Aug 26 '17 at 14:43