加载模板dom时,angular2模板/钩子中的脚本标记

时间:2015-12-07 17:55:59

标签: javascript jquery angular

我很困惑,不知道如何解决我的问题...

简化:我有一个基于绑定创建ulist的组件,如下所示:

@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
  }     
}

组件选择器/主机嵌入在php回显的普通html流中,用于替换预定义的ulist。问题是在正常站点上,使用ulist之后的脚本标记在列表上应用一些jquery魔术。

由于脚本标记在组件模板加载完成之前被回显,因此jquery调用不会找到模板DOM的元素。将脚本标记放在我的模板中(最后)不起作用;它似乎被忽略了。

<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>

此外,该网站使用基础框架,每次向页面添加新元素时(例如,通过外部更新我的组件的绑定),我需要调用$(document).foundation()

所以我的问题是,当我不知道我的模板是否已经完成创建时,如何在我的模板DOM上调用jquery。在我的组件模板中定义时,onload处理程序不起作用。

我读过有关AfterViewInit的内容,但我对此感到不知所措。 有人可以请我朝正确的方向推进我吗?

如何找出组件模板何时完全插入&#34; main&#34; DOM?

2 个答案:

答案 0 :(得分:23)

删除组件模板中的脚本标记。解决方法是在ngAfterViewInit()

中动态创建脚本标记

另见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);
}

另见https://stackoverflow.com/a/9413803/217408

更好的方法是使用require()加载脚本。

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

答案 1 :(得分:8)

我遇到了同样的问题,但另外我不得不加载一些脚本,其中一些可以并行加载,另一些可以串行加载。如果您使用的TypeScript 2.1 or greater具有async/await的原生支持并转换为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)
  })
}

对于可以并行加载的任何脚本,您可以利用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")
}

注意:对于承诺拒绝,您可以尝试在scriptElement.onerror = reject函数中使用loadScript(),但是,在这种情况下我遇到了一些奇怪的行为。如果你希望脚本无论如何都要继续加载,你可能想要在调用onerror时尝试解析promises。