Javascript 加载模板 dom 时,angular2 模板/钩子中的脚本标记
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34140065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
script tag in angular2 template / hook when template dom is loaded
提问by ch40s
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:
简化:我有一个基于绑定创建 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
}
}
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.
组件选择器/主机嵌入在由 php 回显的普通 html 流中,用于替换预定义的 ulist。问题在于,在普通站点上,使用 ulist 后的脚本标记对列表应用了一些 jquery 魔法。
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.
由于脚本标记在我的组件模板加载完成之前被回显,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>
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()
.
此外,该站点使用基础框架,每次向页面添加新元素(例如,通过外部更新我的组件的绑定)时,我都需要调用$(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.
所以我的问题是,当我不知道我的模板是否已完成创建时,如何实现在我的模板 DOM 上调用 jquery。在我的组件模板中定义时,onload 处理程序也不起作用。
I have read about AfterViewInit, but I'm kind of overwhelmed with it. Could someone please push me in the right direction?
我已经阅读了 AfterViewInit,但我对它有点不知所措。有人可以把我推向正确的方向吗?
How can I find out when the template of my component has been fully inserted into the "main" DOM?
我如何知道我的组件的模板何时完全插入到“主”DOM 中?
回答by Günter Z?chbauer
Script tags in component templates are removed. A workaround is to create the script tag dynamically in ngAfterViewInit()
组件模板中的脚本标签被删除。一种解决方法是在ngAfterViewInit()
See also https://github.com/angular/angular/issues/4903
另见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
另见https://stackoverflow.com/a/9413803/217408
A better way might be to just use require()
to load the script.
更好的方法可能是仅用于require()
加载脚本。
See also script tag in angular2 template / hook when template dom is loaded
回答by Andrew Odri
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/awaitand transpiles to ES3/ES5:
我遇到了同样的问题,但另外我不得不加载许多脚本,其中一些可以并行加载,而另一些可以串行加载。如果您使用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)
})
}
For any scripts that can be loaded in parallel, you can take advantage of Promise.all:
对于任何可以并行加载的脚本,您都可以利用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.
注意:对于 promise 拒绝,您可以尝试scriptElement.onerror = reject
在loadScript()
函数中使用,但是,我在这种情况下遇到了一些古怪的行为。如果您希望脚本无论如何都继续加载,您可能需要尝试在调用 onerror 时解析 promise。