I have a spinner/loader element defined in app template (root component's template) like
<!--I have it here so that I don't have to paste it in all my templates-->
<div #spinner></div>
In my child components, I am trying to access it using @ViewChild
but that seems to always return undefined. My code for accessing this in child component is
@ViewChild('spinner', { read: ViewContainerRef }) container: ViewContainerRef; //this is always undefined
However when I place my #spinner
in my child component's HTML, it gets picked up correctly.
Is there a way to get the element defined in parent component in your child component as a ContainerRef
?
I need the view reference to create the component on it dynamically using ComponentFactoryResolver
.
It seems a similar issue but can't find a way to overcome.
EDIT: I am now using a shared service with the observable, but still it doesn't raise an event on .next
.
Here is my code in 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
};
}
In SpinnerService, I have
@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);
}
}
And in the calling component, I have
@Component({
selector: 'edit-auction',
templateUrl: '/auctions/edit.html'
})
export class EditAuctionComponent {
constructor(public spinnerService: SpinnerService) { }
ngAfterViewInit() {
//start the spinner
this.spinnerService.showSpinner();
}
}
In app.module.ts (root module)
@NgModule({
imports: [BrowserModule, FormsModule, HttpModule, routes],
declarations: [..],
providers: [NotificationsService, SpinnerService],
bootstrap: [AppComponent]
})
export class AppModule { }
Accessing data from other components does not sounds good to me.
For what you are trying to do probably best would be to define service which will share observable:
@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();
}
}
Then in your root component you will subscribe to
eventServiceInstance.spinnerStatus.subscribe(state=>{
//thisSpinner.visible = state
})
And now in all other places you will call
eventServiceInstance.showSpinner()
eventServiceInstance.hideSpinner()
PS. To make it works EventService provider should be added in NgModule and not inside of components
Although it's better to use either Output
parameters or a common service for this purpose its possible to inject a component from a child component by:
ViewChild
to the wrapper element and make it accessibleComponentFactoryResolver
by calling createComponent
on the wrapper element ViewContainerRef
entryComponents
of the modulecode is available in 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;
}
}
Child Component:
@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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With