35

I have a global variable to store the list of countries like this:

export var COUNTRY_CODES = ["AD", "AE", "AF" /* and more */];

In one of my component, I'd imported the variable using normal import statement

import { COUNTRY_CODES } from "../constants";

I am able to access this global variable freely in my component code, but failed to achieve something like this on the HTML template:

<option *ngFor="let countryCode of COUNTRY_CODES" [value]="countryCode">{{countryCode | countryName}}</option>

I could just pass along the global variable to component by defining a local variable and assign the global variable to it during initialization.

ngOnInit() {
  this.countryCodes = COUNTRY_CODES;
}

And change the ngFor to loop on this local variable to make it works.

My question: Is this the right way to do? I'm not totally comfortable with defining bridging variables every time I want to use global variables in my template.

Harry Ninh
  • 16,288
  • 5
  • 60
  • 54

5 Answers5

38

You are creating a variable countryCodes in you component but the view is accessing COUNTRY_CODES instead*


Global identifiers like Array, window, document, class and enum names and global variables can't be accessed directly from within the template.

The scope of the template is the component class instance.

What you can do if you need access to any of these, is to create a getter in your component like

import { COUNTRY_CODES } from "../constants";

@Component(...)  
export class MyComponent {
  get countryCodes() { return COUNTRY_CODES; }
  // or countryCodes = COUNTRY_CODES;
}

then it can be used in the template like

<option *ngFor="let countryCode of countryCodes" [value]="countryCode">{{countryCode | countryName}}</option>

Using a shared service like suggested in the other answers works similar. What's the better approach depends on the concrete use case. Services are easy to mock for unit tests in contrary to global variables.

See also

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Worked with a getter, but not with just a plain property. Thanks – Kon Feb 11 '19 at 19:09
  • @GünterZöchbauer - i wonder if this has changed in the newer versions of Angular. I am working in an Angular 11 application and this does not work. The error is "'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.'" – Sofía Aug 01 '22 at 06:24
  • 1
    @Sofia that is a TypeScript limitation if the enum is declared const. You can't access the enum values in code this way for const enums, so Angular also can't. – Günter Zöchbauer Aug 02 '22 at 13:21
  • aah thank you so much! I didn't realize that was causing the problem. Now it works : ) – Sofía Aug 03 '22 at 14:42
3

First #

you should note that there is a problem in your COUNTRY_CODES. you have put two double quotes at beginning.

It should be ,

Export var COUNTRY_CODES=["AD","AE","AF"];

Second #

Once you pass const value to this.countryCode, you should use it in ngfor loop like,

*ngFor = "let cc in countryCode" [value]="cc"

OR

If you directly want to use it within HTML, Id suggest to make a sharedService to define global variable.

UPDATE

Other way is you can use provide function and define your constant there in provide function within bootstrap function then inject it into respective component to use it.

Check out that way here,

Working Example

Pardeep Jain
  • 84,110
  • 37
  • 165
  • 215
micronyks
  • 54,797
  • 15
  • 112
  • 146
1

change this as

export var COUNTRY_CODES = ["AD", "AE", "AF"];

your code have extra " in your array so you have to remove this first than your code run as smothly

working plunker

Pardeep Jain
  • 84,110
  • 37
  • 165
  • 215
  • The downvote is IMHO inappropriate, but your answer is missing the part that the template accesses `COUNTRY_CODES` but the variable is named `countryCodes`. You corrected it in your Plunker but the answer doesn't reflect that. I guess this is the cause for the downvote. – Günter Zöchbauer Jun 10 '16 at 07:33
  • yeah agree but i haven't added that in answer because there is mistake in the Globalvaribale only not in the template so posting juts mistaken part @GünterZöchbauer – Pardeep Jain Jun 10 '16 at 07:47
1

I wanted todo a similar thing, but with a lot of single constants.

Defining a getter for every single one was really annoying - as was the methode of creating a service for these constants, as it meant i could only use them where i can actually inject it ( or again additional work ).

I found that using inline templates, fixed it for me - as it allows to compile the constants into the template - using typescripts multiline `${variable}` template syntax - only thing to look out is that the values have to be wrapped according to their type. Becouse the array.toString() methode would result in '1,2,3,4' so you need to wrap it in "[]"/"'string'" so angular-templating engine picks it up as an array/string again.

Edit: I just saw there was a similar methode mentioned, but i also don't want to inject every single value into the constuctor, as that would be as uncomfortable as defining a member per value.

constants.ts:

export const TEST_STRING = 'route';
export const TEST_ARRAY = [1, 2, 3, 4];

component.ts:

 import {
  TEST_STRING,
  TEST_ARRAY
 } from 'constants.ts'
 @Component({
  selector: 'hn-header',
  template: '
      <a [routerLink]="['${TEST_STRING}']">Link</a>
      <div *ngFor="let test of [${TEST_ARRAY}];">{{test}}</div>
  '
  styleUrls: ['./header.component.css']
 })
 export class HeaderComponent {...}

results in:

<a href="route">Link</a>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
Florian
  • 451
  • 3
  • 13
0

Angular 8/9

...app/global-varibles/globals.ts

export class GlobalVars {
    public static baseUrl:string = "http://localhost:8000/";
    //public static baseUrl:string = "https://myproduction.site.com/";
    public static countries = ["AD","AE","AF"];
}

...app/components/someconsumerpage.ts

import{ GlobalVars } from './../../global-variables/globals';
   
@Component({
  selector: 'some-consumer-page',
  templateUrl: './someconsumerpage.html',
  styleUrls: ['./someconsumerpage.scss']
})
export class HotelsBaseComponent implements OnInit {
  countries = GlobalVars.countries;
  constructor(
  ) { }

}

...app/components/someconsumerpage.html

<h3 *ngFor="let c of countries">{{c}}</h3>
Community
  • 1
  • 1
7guyo
  • 3,047
  • 1
  • 30
  • 31