我在app模板(根组件的模板)中定义了一个微调器/加载器元素,如
<!--I have it here so that I don't have to paste it in all my templates-->
<div #spinner></div>
在我的子组件中,我试图使用@ViewChild
访问它,但似乎总是返回undefined。我在子组件中访问它的代码是
@ViewChild('spinner', { read: ViewContainerRef }) container: ViewContainerRef; //this is always undefined
但是,当我将#spinner
放入我的子组件的HTML中时,它会被正确拾取。
有没有办法让子组件中父组件中定义的元素为ContainerRef
?
我需要视图引用,使用ComponentFactoryResolver
动态创建组件。
这似乎是similar问题,但无法找到克服的方法。
编辑:我现在正在使用带有observable的共享服务,但它仍然没有在.next
上引发事件。
以下是SpinnerComponent
@Component({
selector: 'spinner',
styleUrls: ['app/styles/spinner.component.css'],
template:
`<div [hidden]="state.visible" class="in modal-backdrop spinner-overlay"></div>
<div class="spinner-message-container" aria-live="assertive" aria-atomic="true">
<div class="spinner-message" [ngClass]="spinnerMessageClass">{{ state.message }}</div>
</div>`
})
export class SpinnerComponent {
constructor(spinnerService: SpinnerService) {
spinnerService.spinnerStatus.subscribe(event => {
console.log('Event: ' + event); <= not getting called
this.state.visible = event;
});
}
public state = {
message: 'Please wait...',
visible: false
};
}
在SpinnerService中,我有
@Injectable()
export class SpinnerService {
public events: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public get spinnerStatus(): Observable<boolean> {
return this.events.asObservable();
}
public showSpinner() {
this.events.next(true);
}
public hideSpinner() {
this.events.next(false);
}
}
在调用组件中,我有
@Component({
selector: 'edit-auction',
templateUrl: '/auctions/edit.html'
})
export class EditAuctionComponent {
constructor(public spinnerService: SpinnerService) { }
ngAfterViewInit() {
//start the spinner
this.spinnerService.showSpinner();
}
}
在app.module.ts(根模块)
@NgModule({
imports: [BrowserModule, FormsModule, HttpModule, routes],
declarations: [..],
providers: [NotificationsService, SpinnerService],
bootstrap: [AppComponent]
})
export class AppModule { }
答案 0 :(得分:7)
从其他组件访问数据对我来说听起来不太好。
对于您要做的事情,最好的方法是定义将共享可观察的服务:
@Injectable()
export class EventService {
public selectedCategoryName: string = '';
private events = new BehaviorSubject<Boolean>(false);
constructor() {
}
public showSpinner(){
this.events.next(true)
}
public hideSpinner(){
this.events.next(false);
}
public get spinnerStatus() : Observable<boolean> {
return this.events.asObservable();
}
}
然后在您的根组件中,您将订阅
eventServiceInstance.spinnerStatus.subscribe(state=>{
//thisSpinner.visible = state
})
现在在其他所有地方你都会打电话
eventServiceInstance.showSpinner()
eventServiceInstance.hideSpinner()
PS。为了使其工作,应在NgModule中添加EventService提供程序,而不是在组件
中答案 1 :(得分:1)
尽管为此目的使用Output
参数或公共服务更好,但可以通过以下方式从子组件中注入组件:
ViewChild
添加到包装器元素并使其可访问ComponentFactoryResolver
上调用createComponent
,从子项创建包含ViewContainerRef
的新组件entryComponents
代码可在plunker
中找到app.ts:
@Component({
selector: 'my-app',
template: `
<div>
<h2>App/h2>
<my-child></my-child>
<div #spinner></div>
</div>
`,
})
export class App {
@ViewChild('spinner', { read: ViewContainerRef }) private spinner: any;
public getSpinnerRef() {
return this.spinner;
}
}
子组件:
@Component({
selector: 'my-child',
template: `
<div>
<h3>Child</h3>
</div>
`,
})
export class ChildCmp implements OnInit {
constructor(private app: App, private componentFactoryResolver: ComponentFactoryResolver) {
}
public ngOnInit() {
const spinnerCmp = this.componentFactoryResolver.resolveComponentFactory(SpinnerCmp);
this.app.getSpinnerRef().createComponent(spinnerCmp);
}
}