0

I'm trying to implement an angular2 app that has a dependency on a 3rd party js library, that is getting included in index.html script tag. Trying to implement the sales force external identity solution as outlined here.

this script is looking for some meta tags in the page in order to function properly, whether to pop-up as a model or inline form for example.

I'm using the angular platform browser's Meta functionality to set the meta tags in the page, implemented in the constructor of app.component.ts.

This seems to have created a race condition, as in certain situations (typically, when the script exists in the browser cache) it throws alerts that the required meta tags aren't available.

How can I stop the loading of the script in index.html (I've set it with the defer and async keywords btw) to not load until AFTER the app.component has set the meta tags?

app.component.ts

import {Component, OnInit} from '@angular/core';
import {TodoService} from './providers/todo.service';
import {Meta} from '@angular/platform-browser';
import {environment} from '../environments/environment';
import { isNull } from 'util';


declare var SFIDWidget: any;
declare var SFIDWidget_loginHandler: any;
declare var SFIDWidget_logoutHandler: any;


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [TodoService]
})
export class AppComponent implements OnInit {

  constructor(public meta: Meta) {

    //meta tag stuff

    //check for meta tags and add if not exists
    if (isNull(this.meta.getTag('name="salesforce-logout-handler"'))) {
      this.meta.addTags(
        [
          {
            name: "salesforce-client-id",
            content: `${environment.clientId}`
          },
          {
            name: "salesforce-community",
            content: `${environment.communityURL}`
          },
          {
            name: "salesforce-redirect-uri",
            content: `${environment.redirectURL}`
          },
          {
            name: "salesforce-mode",
            content: "modal"
          },
          {
            name: "salesforce-forgot-password-enabled",
            content: "true"
          },
          {
            name: "self-register-enabled",
            content: "true"
          },
          {
            name: "salesforce-save-access-token",
            content: "true"
          },
          {
            name: "salesforce-target",
            content: "#salesforce-login"
          },
          {
            name: "salesforce-login-handler",
            content: "onLogin"
          },
          {
            name: "salesforce-logout-handler",
            content: "onLogout"
          }
        ], true);
    } else {

      console.log('meta tags exist!');
    }


  }

  ngOnInit() {


  }

  onLogin(identity) {

    console.log('fired from the app component');

  }


  onLogout() {

    SFIDWidget.init();
  }


}

index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Herokudos</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <script
    src="https://sdo-134f326f986sdo-134f326f986.force.com/servlet/servlet.loginwidgetcontroller?type=javascript_widget&min=false&cacheMaxAge=0"
    async defer></script>
  <link
    href="https://sdo-134f326f986sdo-134f326f986.force.com/servlet/servlet.loginwidgetcontroller?type=css"
    rel="stylesheet" type="text/css"/>
</head>
<body>
<app-root>Loading...</app-root>

</body>
</html>
ItamarG3
  • 4,092
  • 6
  • 31
  • 44
adam.sellers
  • 181
  • 5
  • 16
  • If you have the control on the `index.html` file you can change the script type to something that browser won't execute like `type="text/don't-execute"`, and change it to `text/javascript` or just remove it when you're done modifying `Meta` tags. This is brute force of course, in case you can't find anything built in for Angular – 11thdimension Jun 25 '17 at 01:51
  • refer to this answer for loading scripts at runtime https://stackoverflow.com/questions/34489916/load-external-js-script-dynamically-in-angular-2/42766146#42766146 – Rahul Kumar Oct 31 '17 at 15:29

1 Answers1

3

Remove the <script> tag that you hardcoded into index.html. If you want to load scripts that depend on Angular being ready, consider loading them dynamically in the component's ngAfterViewInit() lifecycle hook. This will guarantee that the script will load only after your AppComponent has been rendered.

AppComponent

/*executes once the component template is built*/
ngAfterViewInit(){
    //Add a script tag to the DOM
    let script = document.createElement('script');
    document.body.appendChild(script);

    //listen for the load event on the script...
    Observable.fromEvent(script,'load').first().subscribe(
          //...and call onScriptLoad once the script is loaded
          ()=>this.onScriptLoad()
    );

    //set script source: will trigger the download
    script.src = "https://sdo...";
}

/*executes once the script has been loaded*/
onScriptLoad(){}
BeetleJuice
  • 39,516
  • 19
  • 105
  • 165