web-dev-qa-db-ja.com

angular2テンプレートのscriptタグ/テンプレートdomがロードされたときのフック

私はかなり立ち往生していて、私の問題を解決する方法がわかりません...

簡略化:次のように、バインディングに基づいて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を置き換えるために使用されます。問題は、通常のサイトでは、リストにjqueryマジックを適用するためにulistの後のスクリプトタグが使用されていることです。

スクリプトタグは、コンポーネントのテンプレートの読み込みが完了する前にエコー出力されるため、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について読みましたが、それに圧倒されています。誰かが私を正しい方向に押してくれませんか?

コンポーネントのテンプレートが「メイン」DOMに完全に挿入されたことを確認するにはどうすればよいですか?

12
ch40s

コンポーネントテンプレートのスクリプトタグは削除されました。回避策は、ngAfterViewInit()でスクリプトタグを動的に作成することです

参照 https://github.com/angular/angular/issues/49

_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()を使用してスクリプトをロードすることです。

参照 angular2テンプレートのスクリプトタグ/テンプレートdomが読み込まれたときのフック

23

同じ問題が発生しましたが、さらに、いくつかのスクリプトをロードする必要があり、その一部は並列​​にロードでき、他のスクリプトは直列にロードできました。このソリューションは、 TypeScript 2.1以降 を使用している場合に機能します。これには、 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")
}
_

注:promiseの拒否については、loadScript()関数で_scriptElement.onerror = reject_を使用して試すことができますが、この状況での風変わりな動作。スクリプトのロードを継続したい場合は、onerrorが呼び出されたときにプロミスを解決してみてください。

8
Andrew Odri