Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

script tag in angular2 template / hook when template dom is loaded

I'm pretty stuck and don't know how to solve my problem...

Simplified: I have a component that creates a ulist based on a binding, like this:

@Component({
   selector: "template",
   template: `
     <ul>
       <li *ng-for="#challenge of jobs.challenges">{{challenge}}</li>
     </ul>
   `})
export class JobTemplate{
  jobs: Jobs;
  constructor(jobs:Jobs){
    this.jobs = jobs
  }     
}

The component selector/host is embedded in normal html flow echoed by php and is used to replace a predefined ulist. The problem is that on the normal site, a script tag after the ulist was used to apply some jquery magic on the list.

Since the script tag is echoed out before the template of my component has finished loading, the jquery calls won't find the elements of my template DOM. Putting the script tag inside my template (at the end) does not work; it simply seems to get ignored.

<ul>
  <a><li *ng-for="#challenge of jobs.challenges">{{challenge}}</li></a>  
</ul>
<script>
   $("ul a").on("click", function (event)
        {
        var parent = $(this).parent();
        if(parent.hasClass('active'))
          ....slideToggle("normal");
        else
        ....
        });
</script>

Also the site uses the foundation framework, and each time a new element is added to the page (e.g through the binding of my component being updated externally) I need to call $(document).foundation().

So my question is, how can I achieve to call jquery on my template DOM, when I don't know if my template has finished being created. The onload handler doesn't work either when defined in my component template.

I have read about AfterViewInit, but I'm kind of overwhelmed with it. Could someone please push me in the right direction?

How can I find out when the template of my component has been fully inserted into the "main" DOM?

like image 499
ch40s Avatar asked Dec 07 '15 17:12

ch40s


People also ask

What happens if you use script tag inside template?

Angular recognizes the value as unsafe and automatically sanitizes it, which removes the script tag but keeps safe content such as the text content of the script tag.

Can I use script tag in Angular template?

To eliminate the risk of script injection attacks, Angular does not support the <script> element in templates. Angular ignores the <script> tag and outputs a warning to the browser console. For more information, see the Security page.

Can we add script tag in HTML in Angular?

AngularJS is a JavaScript framework. It can be added to an HTML page with a <script> tag.

How do I add a script tag to a TS file?

To include a JavaScript library in your TypeScript application you must first include it in your HTML file as a script tag. To use the library you must add the following to one of your ts files: declare var libraryVar: any; Replace libraryVar with a variable, function, or class within your JavaScript library.


2 Answers

I encountered the same issue, but additionally I had to load in a number of scripts, some of which could loaded in parallel, and others in series. This solution will work if you are using TypeScript 2.1 or greater, which has native support for async/await and transpiles to ES3/ES5:

async ngAfterViewInit() {
  await this.loadScript("http://sub.domain.tld/first-script.js")
  await this.loadScript("http://sub.domain.tld/second-script.js")
}

private loadScript(scriptUrl: string) {
  return new Promise((resolve, reject) => {
    const scriptElement = document.createElement('script')
    scriptElement.src = scriptUrl
    scriptElement.onload = resolve
    document.body.appendChild(scriptElement)
  })
}

For any scripts that can be loaded in parallel, you can take advantage of Promise.all:

async ngAfterViewInit() {
  await Promise.all([
    this.loadScript("http://sub.domain.tld/first-parallel.js"),
    this.loadScript("http://sub.domain.tld/second-parallel.js")
  ])
  await this.loadScript("http://sub.domain.tld/after-parallel.js")
}

Note: For promise rejection, you can try working with scriptElement.onerror = reject in the loadScript() function, however, I encountered some quirky behavior in this situation. If you want script to keep loading no matter what, you may want to experiment with resolving promises when onerror is called.

like image 101
Andrew Odri Avatar answered Nov 09 '22 13:11

Andrew Odri


Script tags in component templates are removed. A workaround is to create the script tag dynamically in ngAfterViewInit()

See also https://github.com/angular/angular/issues/4903

constructor(private elementRef:ElementRef) {};

ngAfterViewInit() {
  var s = document.createElement("script");
  s.type = "text/javascript";
  s.src = "http://somedomain.com/somescript";
  this.elementRef.nativeElement.appendChild(s);
}

See also https://stackoverflow.com/a/9413803/217408

A better way might be to just use require() to load the script.

See also script tag in angular2 template / hook when template dom is loaded

like image 21
Günter Zöchbauer Avatar answered Nov 09 '22 13:11

Günter Zöchbauer