[英]How to pass variables from ng-template declared in parent component to a child component/directive?
所以我想知道是否有辦法傳遞ng-template並生成所有內容以包含插值中使用的變量?
另外我還是新角色所以除了刪除html元素之外,我還需要擔心刪除其他內容嗎?
最后會有一個指向stackblitz.com repo的鏈接,它將包含下面顯示的所有代碼。
以下是我的src / app / app.component.html代碼實現我的指令:
<hello name="{{ name }}"></hello>
<p>
Start editing to see some magic happen :)
</p>
<!-- popup/popup.directive.ts contains the code i used in button tag -->
<button PopupDir="" body="this is a hardcoded message that is passed to popup box"> simple
</button>
<ng-template #Complicated="">
<div style="background-color: red;">
a little more complicated but simple and still doable
</div>
</ng-template>
<button PopupDir="" [body]="Complicated">
complicated
</button>
<ng-template #EvenMoreComplicated="">
<!-- name and data isn't being passed i need help here-->
<div style="background-color: green; min-height: 100px; min-width:100px;">
{{name}} {{data}}
</div>
</ng-template>
<button PopupDir="" [body]="EvenMoreComplicated">
more complicated
</button>
以下是我的src / app / popup / popup.directive.ts
import { Directive, Input, TemplateRef, ViewContainerRef, HostListener } from '@angular/core'
@Directive({
selector: 'PopupDir, [PopupDir]'
})
export class Popup {
@Input() body: string | TemplateRef<any>;
viewContainer: ViewContainerRef;
popupElement: HTMLElement;
//i dont know if i need this
constructor (viewContainer: ViewContainerRef) {
this.viewContainer = viewContainer;
}
//adds onlick rule to parent tag
@HostListener('click')
onclick () {
this.openPopup();
}
openPopup() {
//Pcreate pupup html programatically
this.popupElement = this.createPopup();
//insert it in the dom
const lastChild = document.body.lastElementChild;
lastChild.insertAdjacentElement('afterend', this.popupElement);
}
createPopup(): HTMLElement {
const popup = document.createElement('div');
popup.classList.add('popupbox');
//if you click anywhere on popup it will close/remove itself
popup.addEventListener('click', (e: Event) => this.removePopup());
//if statement to determine what type of "body" it is
if (typeof this.body === 'string')
{
popup.innerText = this.body;
} else if (typeof this.body === 'object')
{
const appendElementToPopup = (element: any) => popup.appendChild(element);
//this is where i get stuck on how to include the context and then display the context/data that is passed by interpolation in ng-template
this.body.createEmbeddedView(this.viewContainer._view.context).rootNodes.forEach(appendElementToPopup);
}
return popup;
}
removePopup() {
this.popupElement.remove();
}
}
這是顯示我的問題的回購鏈接: https : //stackblitz.com/edit/popupproblem
首先讓我們思考一下我們如何將上下文傳遞給嵌入式視圖。 你寫了:
this.body.createEmbeddedView(this.viewContainer._view.context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
您的Popup
組件托管在AppComponent
視圖中,因此this.viewContainer._view.context
將是AppComponent
實例。 但是我想讓你說出來:
1)嵌入式視圖已經可以訪問定義了ng-template
的模板范圍。
2)如果我們傳遞上下文,那么它應該只用於模板引用變量。
this.body.createEmbeddedView(this.viewContainer._view.context)
||
\/
this.body.createEmbeddedView({
name = 'Angular';
data = 'this should be passed too'
})
||
\/
<ng-template #EvenMoreComplicated let-name="name" let-data="data">
{{name}} {{data}}
所以在這種情況下,您不需要傳遞上下文,因為它已經存在。
this.body.createEmbeddedView({})
||
\/
<ng-template #EvenMoreComplicated>
{{name}} {{data}}
角度變化檢測機制依賴於視圖樹。
AppComponent_View
/ \
ChildComponent_View EmbeddedView
|
SubChildComponent_View
我們看到有兩種視圖:組件視圖和嵌入視圖。 TemplateRef
(ng-template)表示嵌入視圖。
當Angular想要更新UI時,它只需通過該視圖兩個檢查綁定。
現在讓我們提醒我們如何通過低級API創建嵌入式視圖:
TemplateRef.createEmbeddedView
ViewContainerRef.createEmbeddedView
它們之間的主要區別在於前者只是創建了EmbeddedView,而后者創建了EmbeddedView, 並將其添加到Angular變化檢測樹中 。 這種嵌入式視圖成為變更檢測樹的一部分,我們可以看到更新的綁定。
是時候看你的代碼了:
this.body.createEmbeddedView(this.viewContainer._view.context).rootNodes.forEach(appendElementToPopup);
應該清楚你正在使用第一種方法。 這意味着您必須自己處理更改檢測:手動調用viewRef.detectChanges()
或附加到樹。
簡單的解決方案是:
const view = this.body.createEmbeddedView({});
view.detectChanges();
view.rootNodes.forEach(appendElementToPopup);
但它只會檢測一次變化。 我們可以在每個Popup.ngDoCheck()
鈎子上調用detectChanges
方法,但Angular本身使用的方法更簡單。
const view = this.viewContainer.createEmbeddedView(this.body);
view.rootNodes.forEach(appendElementToPopup);
我們使用第二種創建嵌入視圖的方法,以便Angular自動檢查模板。
我仍然是新角色所以除了刪除html元素之外我還需要擔心刪除其他內容嗎?
我認為在關閉彈出窗口時我們也應該銷毀嵌入式視圖。
removePopup() {
this.viewContainer.clear();
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.