Javascript 如何使用模板引用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36266453/
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
How to use templateRef?
提问by Kris Hollenbeck
I am trying to find a way to dynamically construct a template in Angular2. I was thinking templateRef might provide a way to do this. But I could be wrong.
我试图找到一种在 Angular2 中动态构建模板的方法。我在想 templateRef 可能会提供一种方法来做到这一点。但我可能是错的。
I found an example of templateRef being used here.
I was looking at templateRef in this example. I noticed the syntax is [ng-for-template]
I also tried [ngForTemplate]
cause I know this has changed recently.
我在这个例子中查看了 templateRef。我注意到语法是[ng-for-template]
我也尝试过,[ngForTemplate]
因为我知道这最近发生了变化。
So at the moment I have this:
所以目前我有这个:
import {Component, TemplateRef} from 'angular2/core';
@Component({
selector : 'body',
template : `
<template [ngForTemplate]="container">
<div class="container"></div>
</template>
`
})
export class App
{
@ContentChild(TemplateRef) container;
constructor() {}
ngAfterContentInit()
{
console.log(this);
}
}
This example throws an error:
这个例子抛出一个错误:
Can't bind to 'ngForTemplate' since it isn't a known native property
无法绑定到“ngForTemplate”,因为它不是已知的本机属性
So firstly I am wondering. What is the right way to do this? The docs don't provide any examples.
所以首先我想知道。这样做的正确方法是什么?文档没有提供任何示例。
Secondly, is there a good way I can add new template logic to my template or dynamically construct a template? The structure of the application can be a very large amount of different structural combinations. So if possible I would like to see if there is a way I can do this without having a huge template with a bunch of different ngIf and ngSwitch statements..
其次,有没有什么好的方法可以向我的模板中添加新的模板逻辑或动态构建模板?应用程序的结构可以是非常大量的不同结构组合。因此,如果可能的话,我想看看是否有一种方法可以做到这一点,而无需使用包含一堆不同 ngIf 和 ngSwitch 语句的巨大模板。
My question is really the first part about templateRef. But any help or suggestions on the second part is appreciated.
我的问题实际上是关于 templateRef 的第一部分。但对第二部分的任何帮助或建议表示赞赏。
采纳答案by Eric Martinez
Creating your own template directive it's not difficult, you have to understand two main things
创建您自己的模板指令并不难,您必须了解两个主要内容
TemplateRef
contains what's inside your<template>
tagViewContainerRef
as commented by Gunter, holds the template's view and will let you to embed what's inside the template into the view itself.
TemplateRef
包含您的<template>
标签内的内容ViewContainerRef
正如 Gunter 评论的那样,持有模板的视图,并允许您将模板内的内容嵌入到视图本身中。
I will use an example I have when I tried to solve this issue, my approach is not the best for that, but it will work for explaining how it works.
当我试图解决这个问题时,我将使用一个例子,我的方法不是最好的,但它可以解释它是如何工作的。
I want to clarify too that you can use any attribute for your templates, even if they're already used by builtin directives (obviously this is not a good idea, but you can do it).
我也想澄清一下,您可以为模板使用任何属性,即使它们已经被内置指令使用(显然这不是一个好主意,但您可以这样做)。
Consider my approach for ngIfIn
(my poor approach)
考虑我的方法ngIfIn
(我糟糕的方法)
<template [ngIfValue]="'make'" [ngIfIn]="obj">
This will print
</template>
<template [ngIfValue]="'notExistingValue'" [ngIfIn]="obj">
This won't print
</template>
We have here two templates using two inputs each ngIfIn
and ngIfValue
, so I need my directive to grab the template by these two inputs and get their values too, so it would look like this
在这里,我们有使用每两个输入两个模板ngIfIn
和ngIfValue
,所以我需要我的指令抓住这两个输入模板,并得到他们的价值观也一样,所以它看起来像这样
@Directive({
selector : '[ngIfIn][ngIfValue]',
inputs : ['ngIfIn', 'ngIfValue']
})
First I need to inject the two classes I mentioned above
首先我需要注入我上面提到的两个类
constructor(private _vr: ViewContainerRef, private _tr: TemplateRef) {}
I also need to cache the values I'm passing through the inputs
我还需要缓存我通过输入传递的值
_value: any;
_obj: any;
// Value passed through <template [ngIfValue]="'...'">
set ngIfValue(value: any) {
this._value = value;
}
// Value passed through <template [ngIfIn]="...">
set ngIfIn(obj: any) {
this._obj = obj;
}
In my case I depend on these two values, I could have my logic in ngOnInit
but that would run once and wouldn't listen for changes in any of the inputs, so I put the logic in ngOnChanges
. Remember that ngOnChanges
is called right after the data-bound properties have been checked and before view and content children are checked if at least one of them has changed(copy and paste from the docs).
在我的情况下,我依赖于这两个值,我可以将我的逻辑放入ngOnInit
但它会运行一次并且不会监听任何输入的变化,所以我将逻辑放入ngOnChanges
. 请记住,在检查数据绑定属性之后和检查视图和内容子项之前,如果其中至少一个已更改(从文档中复制和粘贴),将立即调用它。ngOnChanges
Now I basically copy & paste NgIflogic (not so complex, but similar)
现在我基本上复制和粘贴NgIf逻辑(不是那么复杂,但类似)
// ngOnChanges so this gets re-evaluated when one of the inputs change its value
ngOnChanges(changes) {
if(this._value in this._obj) {
// If the condition is true, we embed our template content (TemplateRef) into the view
this._vr.createEmbeddedView(this._tr);
} else {
// If the condition is false we remove the content of the view
this._vr.clear();
}
}
As you see it's not that complicated : Grab a TemplateRef, grab a ViewContainerRef, do some logic and embed the TemplateRef in the view using ViewContainerRef.
如您所见,它并没有那么复杂:获取一个 TemplateRef,获取一个 ViewContainerRef,执行一些逻辑并使用 ViewContainerRef 将 TemplateRef 嵌入到视图中。
Hopefully I made myself clear and I made how to use them clear enough also. Here's a plnkrwith the example I explained.
希望我说清楚了,我也清楚地说明了如何使用它们。这是我解释的示例的plnkr。
回答by Günter Z?chbauer
ngForTemplate
is only supported with ngFor
ngForTemplate
仅支持 ngFor
<template [ngFor] [ngForOf]="..." [ngForTemplate]="container"
or
或者
<div *ngFor="..." [ngForTemplate]="container"
not on a plain template. It is an @Input()
on the NgFor
directive
不是在一个普通的模板上。这是一个@Input()
对NgFor
指令
Another way to use TemplateRef
另一种使用方式 TemplateRef
If you have a reference to ViewContainerRef
you can use it to "stamp" the template
如果你有一个参考,ViewContainerRef
你可以用它来“标记”模板
constructor(private _viewContainer: ViewContainerRef) { }
ngOnInit() {
this.childView = this._viewContainer.createEmbeddedView(this.templ);
this.childView.setLocal('data', this.data);
}