Сначала давайте подумаем, как мы передаем контекст во встроенное представление.Вы писали:
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 хочет обновить пользовательский интерфейс, он просто проходит через это представление две контрольные привязки.
Теперь давайте напомним, как мы можем создать встроенное представление с помощью низкоуровневого API:
Основное различие между ними заключается в том, что первый просто создает EmbeddedView, а второй -EmbeddedView, а также добавляет его в дерево обнаружения угловых изменений .Таким образом, встроенное представление становится частью дерева обнаружения изменений, и мы можем видеть обновленные привязки.
Пришло время увидеть ваш код:
this.body.createEmbeddedView(this.viewContainer._view.context).rootNodes.forEach(appendElementToPopup);
Должно быть ясно, что вы используете первыйподход.Это означает, что вы должны позаботиться об обнаружении изменений самостоятельно: либо позвоните viewRef.detectChanges()
вручную, либо подключитесь к дереву.
Простое решение может быть:
const view = this.body.createEmbeddedView({});
view.detectChanges();
view.rootNodes.forEach(appendElementToPopup);
Пример Stackblitz
Но он обнаружит изменения только один раз.Мы могли бы вызывать метод detectChanges
на каждом хуке Popup.ngDoCheck()
, но есть более простой способ, который используется самим Angular.
const view = this.viewContainer.createEmbeddedView(this.body);
view.rootNodes.forEach(appendElementToPopup);
Мы использовали второй подход для создания встроенного представления, так что шаблон будет автоматическипроверено самим Angular.
Я все еще новичок в angular, поэтому помимо удаления html-элемента мне нужно беспокоиться об удалении чего-либо еще?
Я думаю, что мы должнытакже уничтожить встроенный вид при закрытии всплывающего окна.
removePopup() {
this.viewContainer.clear();
...
}
Окончательный пример Stackblitz