Вы не можете использовать вывод здесь, так как вы не можете получить вывод из включенного контента, но есть несколько способов сделать sh это ...
все это зависит от TemplateRef
введите ViewChild
или ContentChildren
, все из которых можно импортировать из angular core:
import { TemplateRef, ViewChild, ContentChildren } from '@angular/core'
Использование общего сервиса
Вы можете использовать сервис для передачи шаблонов довольно эффективно.
рассмотрим простой сервис для передачи шаблонов через субъект, например:
@Injectable()
export class TemplateService {
// allow undefined for resetting
private templateSource = new Subject<TemplateRef<any> | undefined>()
template$ = this.templateSource.asObservable()
setTemplate(template?: TemplateRef<any>) {
this.templateSource.next(template)
}
}
и хост-компонент, который предоставляет и подписывается на него:
@Component({
selector: 'host',
templateUrl: './host.component.html',
// providing the service here makes sure the children of the component (and ONLY this children of this component) will have access to the same service instance
providers: [TemplateService]
})
export class HostComponent {
childTemplate?: TemplateRef<any>
constructor(private templateService: TemplateService) {
// receive templates from the service and assign
this.templateService.template$.subscribe(t => this.childTemplate = t)
}
}
с шаблоном, который определяет ngTemplateOutlet:
<div>
<h1>Host Content</h1>
<ng-container *ngTemplateOutlet="childTemplate"></ng-container>
</div>
<ng-content></ng-content>
* ПРИМЕЧАНИЕ: вы сказали, что переключаете содержимое внутри своего компонента довольно часто, я предполагаю, что вы используете ng-content
, чтобы сделать это, но этот метод будет одинаково хорошо работает с выходом маршрутизатора.
затем дочерний компонент, который отправляет шаблон через службу:
@Component({
selector: 'child1',
templateUrl: './child1.component.html',
})
export class Child1Component {
// access template with ViewChild
@ViewChild('childTemplate')
childTemplate?: TemplateRef<any>
constructor(private templateService: TemplateService) {
}
ngAfterViewInit() {
// set here in afterViewInit hook when ViewChild is available
this.templateService.setTemplate(this.childTemplate)
}
ngOnDestroy() {
// need to clean up
this.templateService.setTemplate()
}
childFunc() {
console.log('child func called')
}
}
с шаблоном, который определяет шаблон для передачи с помощью ng-template:
<h2>Child 1 Content</h2>
<ng-template #childTemplate><button (click)="childFunc()">Run Child Func</button></ng-template>
используйте это так: * 103 1 *
<host>
<child1></child1>
</host>
это эффективно передаст дочерний шаблон от дочернего к хосту, а функции, определенные в этом шаблоне, все еще будут выполняться в дочернем. Единственный настоящий недостаток в том, что вам нужно убедиться, что вы убираете себя в хуке onDestroy. Если у данного ребенка нет специального шаблона, это тоже хорошо. Просто ничего не будет в шаблоне розетки. Если дочерние компоненты должны быть доступны в других контекстах, просто пометьте templateService как необязательный и установите шаблон только в том случае, если он предоставляется.
blitz (расширен заголовком / нижним колонтитулом): https://stackblitz.com/edit/angular-7-master-v81afu
Использование дочерних элементов контента
Альтернативой является использование ContentChildren, если вы определили свой хост таким же образом (тот же шаблон и дочерние элементы, что и раньше, но без вспомогательного содержимого):
@Component({
selector: 'host',
templateUrl: './host.component.html',
})
export class HostComponent {
childTemplate?: TemplateRef<any>
// use content children to access projected content
@ContentChildren('child')
children: QueryList<any>
ngAfterContentInit() {
// set from initial child
this.childTemplate = (this.children.first || {}).childTemplate
// listen for changes and reset
this.children.changes.subscribe(child => {
this.childTemplate = (child.first || {}).childTemplate
})
}
}
тогда вам просто нужно пометить возможных дочерних элементов при использовании вашего хоста:
<host>
<child1 #child></child1>
</host>
Здесь вы должны убедиться, что у вас есть только один отмеченный дочерний контент, доступный одновременно. , В противном случае он просто возьмет первый (или вы можете определить любой лог c, который вы хотите найти шаблон, который вы хотите). Нулевые проверки делают ребенка без шаблона совершенно приемлемым.
блиц (расширенный с верхним / нижним колонтитулом): https://stackblitz.com/edit/angular-7-master-8gc4yb
ВАЖНО: В любом случае вы ДОЛЖНЫ убирать. удержание ссылки на шаблон дочернего элемента в хосте после уничтожения дочернего элемента создает потенциальную возможность утечки памяти или некорректного поведения, поскольку дочерние элементы не смогут быть уничтожены или правильно собран мусор.
Метод обслуживания является более общим / гибким, например, вы можете легко передать шаблон от дочерних элементов, или вы можете легко переключить шаблон из дочернего элемента, или вы можете сделать это с выходом маршрутизатора вместо включения. Но ContentChildren немного проще, хотя он работает только с ng-контентом. Оба одинаково действительны, но зависят от вашего варианта использования.