67

I am using angular6, in my project I am using Facebook Account Toolkit for mobile verification purpose.

I need to initialise Account toolkit in index.html file using following code.

  AccountKit.init({
   appId:"XX",
   state:"xx",
   version:"v1.2",
   fbAppEventsEnabled:true,
   debug:true
 });

The problem is, values for appId and state change depending on environment (development/test/production).

How can I use environment variables in index.html file.

Please let me know if anyone has a solution for angular 6.

starball
  • 20,030
  • 7
  • 43
  • 238
Shavareppa
  • 990
  • 1
  • 6
  • 14

9 Answers9

86

You should create copy of index.html and name it index.someenv.html. Then in your angular.json in environment configuration setup file replacement:

"fileReplacements": [
    {
        "replace": "src/index.html",
        "with": "src/index.someenv.html"
    }
]

The angular cli will replace these files when you run your build

UPD: For Angular 8+ use this:

Add the following to your angular.json:

"production": {
  "index": {
    "input": "src/index.someenv.html",
    "output": "index.html"
  },
},
Artem Krasniuk
  • 1,099
  • 7
  • 6
  • 2
    I am doing this but for some reason it still copies over the original index.html file. I am using the following command to build the angular app: `ng build --prod -c production --output-path dist`. Do you have any idea why it wouldn't replace the index.html file with index.prod.html ? – Dejan Bogatinovski Nov 13 '19 at 00:35
  • 1
    @DejanBogatinovski can you show your configuration for production? (in angular.json) – Artem Krasniuk Nov 14 '19 at 09:20
  • Here it is: https://www.dropbox.com/s/jysqkn9pf5z39y4/Screenshot_1.png?dl=1 – Dejan Bogatinovski Nov 14 '19 at 23:45
  • I am facing the same issue with replacing index ("index.html" not getting replaced with "index.prod.html"). However, this solution is working for {"replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" }. – Joseph Horsch Nov 15 '19 at 15:18
  • 2
    @JosephHorsch only the content of index.html will be replaced, not the filename. – Artem Krasniuk Nov 20 '19 at 13:07
  • 14
    @DejanBogatinovski As of angular 8, you can't replace index files via `"fileReplacements"`. You have to specify your own index file via `"index"` property. Eg.: `"index":"src/index.someenv.html"`. – Rado Koňuch May 04 '20 at 09:40
  • 1
    See [my answer](https://stackoverflow.com/a/62104390/494560) for Angular 8 and above – jcroll May 30 '20 at 15:09
47

This answer supersedes Artyom's answer for Angular 8 and above. Add the following to your angular.json:

"production": {
  "index": {
    "input": "src/index.someenv.html",
    "output": "index.html"
  },
},
jcroll
  • 6,875
  • 9
  • 52
  • 66
  • This would also be great to do in a CI build. have index.tokens.html contain __MY_PLACEHOLDER__. index.html contains the default for local development, and in your pipeline just before your prod build do a replacement of __MY_PLACEHOLDER__ with a pipeline variable. This allows values like environment URLs to be stored in the pipeline and a change to them would be to simply re-run the pipeline for a given commit to generate the file with the new URL instead of needing a code change to have to be promoted through various environments. – Alex Beardsley Jun 09 '21 at 12:25
6

An example here for document.write(environment.variable) : https://github.com/angular/angular-cli/issues/4451#issuecomment-285026543

import { environment } from './environments/environment';

if (environment.production) {
  document.write('<script type="text/javascript">// ProductionAnalyticsCodeHere</script>');
} else if (environment.staging) {
  document.write('<script type="text/javascript">// StagingAnalyticsCodeHere</script>');
}
Arnaud D
  • 81
  • 2
  • 6
  • 2
    This one is kinda dangerous, because `document.write` will replace *whole* HTML document if invoked after page is being loaded. – Tomas Dec 11 '19 at 12:04
5

In main.ts file you can use document.write(environment.variable) and it will write what you want in index.html

(I use it to make the Google Analytics script take a dynamic Tracking ID wether it's in development or production mode, and it works well in Angular6)

0x29A
  • 51
  • 1
  • 1
  • 12
    Hi, would you have a small example to show how you managed to update your Analytics script Tracking ID in your index.html file? Much appreciated – Glenster Aug 22 '19 at 05:14
5

for me above answers did not work on Angular 10, so I created different folder for staging, production etc and placed the index.html which was used by CLI as per the build environment

{
  "projects": {
    "yourApp": {
      "projectType": "application",
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "index": "src/index.html",
          },
          "configurations": {
            "production": {
              "index": "src/production/index.html",
            }
          }
        }
      }
    }
  }
}     
44kksharma
  • 2,740
  • 27
  • 32
  • I confirm, This solution worked for me, on angular 13 – Lokinder Singh Chauhan Aug 04 '22 at 04:18
  • OK, that's weird. I was set to also confirm that jscroll's solution didn't work in Ang 13/14: (`Index html generation failed \r\n ENDENT: no such file or directory, open C:\blah\blah\ClientApp\src\index.test.html`), but after I successfully followed this solution and then tried it again (just to test/report whether it was the name of the index file or whether it needed to be in its own folder), jscroll's solution started working. Go figure. – mcalex Aug 10 '22 at 05:31
2

Avoid direct access to the document object by injecting DOCUMENT to your AppComponent.

import { DOCUMENT } from '@angular/common';
...
  public constructor(
    @Inject(DOCUMENT) private doc: any
  ) {

Add the tag in ngOnInit()

ngOnInit() {
    this.setYourScriptTag();
}

private function to set it

  private setYourScriptTag() {
    const s = this.doc.createElement('script');
    s.type = 'text/javascript';
    s.innerHTML = `AccountKit.init({
   appId: "${environment.appId}",
   state: "${environment.state}",
   version:"v1.2",
   fbAppEventsEnabled:true,
   debug:true
 });`;
    const head = this.doc.getElementsByTagName('head')[0];
    head.appendChild(s);
  }

This answer is from edodusi

https://github.com/angular/angular-cli/issues/4451#issuecomment-384992203

Raul Nohea Goodness
  • 2,549
  • 23
  • 24
1

I think you can do it all in main.ts

const env = environment;

 AccountKit.init({
   appId:env.appId,  // this lane
   state:env.state,  // this lane
   version:"v1.2",
   fbAppEventsEnabled:true,
   debug:true
});

Thanks.

T04435
  • 12,507
  • 5
  • 54
  • 54
  • I had a similar issue with loading google charts js and needing to pass the correct api from the environment variables. Moving the initialize call to main.ts worked for me. Of course timing issues are always a concern when loading/initializing scripts so let us know if it works in your scenario. – Meliovation Feb 22 '19 at 11:27
0

I added this in main.ts:

var html = document.documentElement.innerHTML
document.documentElement.innerHTML = html.replace("Replace me!", environment.variable)

Note that the old value will still exist in index.html for some time while the page is initially loading. (For example, use this to replace the page title and you'll see the old value displayed before the replace happens.)

ZX9
  • 898
  • 2
  • 16
  • 34
  • 2
    FWIW: There is an alternate for setting the title that does not suffer from above @ZX9 mentioned latency, per the Angular docs - https://angular.io/guide/set-document-title. – redevill Jun 10 '20 at 20:49
-4

import your environment file into .ts file.

import { environment } from '../../environments/environment';

Create required fields in your class, assign values from environment to these variables in the constructor, use usual binding in the .html file.

.ts

import { Component } from '@angular/core';
import { environment } from '../environments/environment';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  public production = true;
  constructor() {
    this.production = environment.production;
  }
}

.html

<span>{{production}}</span>
Igor Litvinovich
  • 2,436
  • 15
  • 23
  • 4
    thanks, Igor Litvinovich, but I want to use that env variable in index.html , not in .ts file to that particular html file, i am using angular6. and import not working in index.html file. – Shavareppa Aug 28 '18 at 09:00