@ComptentChild对于DynamicComponentLoader为空

时间:2016-03-13 16:31:40

标签: angular

我有一个侧导航组件可以在很多页面上使用。这不是单页面的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;属性的问题),但我认为如果我可以让它工作,这将是一个更简单的解决方案

2 个答案:

答案 0 :(得分:1)

正如Günter在他关于@ContentChild的回答中建议的那样,除此之外,您可以考虑这一点,
As discussed with Günter - see plunker
对不起,我没有深入了解您的傻瓜,也没有想要进一步实现。但是,如果您要实现ViewChild api,请考虑实现AfterViewInit挂钩。它也适用于DynamicComponentLoader

答案 1 :(得分:0)

有几个问题

  • LoadAsRoot不会调用更改检测

目前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>

  • 的内容