我有一个侧导航组件可以在很多页面上使用。这不是单页面的Web应用程序。它会在切换菜单的父组件上动态加载。 ContentChild用于获取子组件的句柄,以便通过设置@input overlayHidden来切换它。问题是ContentChild为null。
在调试控制台打开的情况下运行此plunker。点击"仪表板"从第一页,然后"切换菜单"从第二页看到空指针。
我做错了什么?
这是代码。
import { Component, Input} from 'angular2/core';
import { Router } from 'angular2/router';
@Component({
selector: 'side-navigation',
template: `
<div id="overlay" [hidden]="overlayHidden">
<div id="wrapper">
<nav id="menu" class="white-bg active" role="navigation">
<ul>
<li><a href="#">Dashboard</a></li>
<li><a href="#">Help & FAQs</a></li>
<li><a href="#">Contact Us</a></li>
<li><a href="#">Log Out</a></li>
</ul>
</nav>
</div>
</div>
`
})
export class SideNavigationComponent {
@Input() overlayHidden: boolean;
}
import { Component,
DynamicComponentLoader,
Injector,
ContentChild, AfterContentInit
} from 'angular2/core';
import { Router, RouterLink } from 'angular2/router';
import { SideNavigationComponent } from './side-navigation';
@Component({
selector: 'dashboard',
template: `
<side-navigation id="side-navigation"></side-navigation>...
`,
directives: [
RouterLink,
SideNavigationComponent ]
})
export class DashboardComponent {
title = 'Dashboard';
@ContentChild(SideNavigationComponent)
sideNavigationComponent: SideNavigationComponent;
constructor(private _router: Router,
private _dcl: DynamicComponentLoader,
private _injector: Injector) {
this._router = _router;
this._dcl = _dcl;
this._injector = _injector;
this._dcl.loadAsRoot(
SideNavigationComponent,
'#side-navigation', this._injector);
}
toggleOverlay() {
this.overlayHidden = !this.overlayHidden;
this.sideNavigationComponent.overlayHidden = this.overlayHidden;
}
}
我构建了一个可行的发布/订阅解决方案(除了覆盖div的隐藏&#39;属性的问题),但我认为如果我可以让它工作,这将是一个更简单的解决方案
答案 0 :(得分:1)
正如Günter在他关于@ContentChild
的回答中建议的那样,除此之外,您可以考虑这一点,
As discussed with Günter - see plunker
对不起,我没有深入了解您的傻瓜,也没有想要进一步实现。但是,如果您要实现ViewChild
api,请考虑实现AfterViewInit
挂钩。它也适用于DynamicComponentLoader
。
答案 1 :(得分:0)
有几个问题
目前loadAsRoot()
仅用于引导根组件(AppComponent
),并且根组件不支持输入。
此评论https://github.com/angular/angular/issues/6370#issuecomment-193896657
中解释了一种解决方法使用loadAsRoot时,您需要触发更改检测并手动连接输入,输出,注入器和组件配置功能
function onYourComponentDispose() {
}
let el = this.elementRef
let reuseInjectorOrCreateNewOne = this.injector;
this.componentLoader.loadAsRoot(YourComponent, this.elementRef, reuseInjectorOrCreateNewOne, onYourComponentDispose)
.then((compRef: ComponentRef) => {
// manually include Inputs
compRef.instance['myInputValue'] = {res: 'randomDataFromParent'};
// manually include Outputs
compRef.instance['myOutputValue'].subscribe(this.parentObserver)
// trigger change detection
cmpRef.location.internalElement.parentView.changeDetector.ref.detectChanges()
// always return in a promise
return compRef
});
此评论https://github.com/angular/angular/issues/7453#issuecomment-193138577还包含指向演示解决方法的Plunker示例的链接
不能在constructor()
中使用DynamicComponentLoader。此代码应移至ngAfterViewInit()
:
this._dcl.loadAsRoot( SideNavigationComponent, &#39;#side-navigation&#39;,this._injector);
正如@Miconyks所指出的那样@ViewChild()
应该用来代替@ContentChild()
。 @ContentChild()
用于传递给<ng-content>