Smokey Dawson
Smokey Dawson

Reputation: 9230

Cannot read property of undefined @ViewChild not working Angular 5

I'm having a bit of trouble I cant seem to figure out why my @ViewChild isnt working..

Basically I want to call a function in one component from another component so in my sidebar component I have a function called sendData() and I want to be able to call that from a button click in my header component so what Ive done is..

Sidebar component

 import { Component, OnInit, Input, OnChanges, SimpleChanges, AfterViewInit } from '@angular/core';

import * as _ from 'lodash';


@Component({
   selector: 'app-sidebar',
   templateUrl: './sidebar.component.html',
   styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent implements OnInit, OnChanges {

constructor(
    private contenfulService: ContentfulService,
    private userService: UserService
) { }

ngOnInit() {

}

sendData(){
    ...do something
}
}

header.component.ts

 import { Component, OnInit, Input, ViewChild, EventEmitter } from '@angular/core';
 import { UserService } from '../../../user.service';
 import { SidebarComponent } from '../sidebar/sidebar.component';

 @Component({
   selector: 'app-program-header',
   templateUrl: './program-header.component.html',
   styleUrls: ['./program-header.component.scss']
 })

 export class ProgramHeaderComponent implements OnInit {
 @ViewChild(SidebarComponent) sidebar;

    constructor() { }

    ngOnInit() {

    }
 }

header.component.html

<div (click)="sidebar.sendData()"></div>

but it isnt working Im getting this error in the console...

ERROR TypeError: Cannot read property 'sendData' of undefined

I have removed code for brevity, so please let me know if there is more information you need

Im not sure what the problem is?

EDIT

Or if anyone knows another way to call a function from a seperate component let me know

Any help would be appreciated!

Thanks!

Upvotes: 1

Views: 19290

Answers (5)

sglugove
sglugove

Reputation: 71

You can always name the component using a # symbol.

HTML template:

<app-sidebar #sidebar1></app-sidebar>

TS code:

@ViewChild('sidebar1') sidebar: any;

You can import the type of your component instead of 'any'.

Hope this helps ;-)

Upvotes: 0

me-and-viy
me-and-viy

Reputation: 109

In my case - it was the import from "@shared" which has caused this issue. You have to pay attention, that the component you are using the @ViewChild component reference is not in the same module with same shorthand path. If it is, import the @ViewChild component from

'shared/components/sidebar/sidebar.component'

and not from '@shared'

Upvotes: 0

MapLion
MapLion

Reputation: 1131

Just as an addition to this conversation, I have been squirreled off on a couple of occasions chasing what seemed to be the lack of a functioning @ViewChild when the cause was the @ViewChild referencing a component in a module that was not being imported. The "cannot read property of undefined" can become extremely misleading and may not be related to @ViewChild at all; be sure to check your imports first.

Upvotes: 2

Pengyy
Pengyy

Reputation: 38171

ViewChild is expected to be used to get target element from current component's view(template) which matches the selector.

But according to your comment above, it seems there is no app-sidebar placed in your header.component.html, so ViewChild is not able to get a valid element which results in your current error.

The solution should be place app-sidebar at least once.

<app-sidebar></app-sidebar>
<div (click)="sidebar.sendData()"></div>

Upvotes: 2

Ali
Ali

Reputation: 1448

If header and sidebar components are siblings, you can not pass data between them directly. Take a look at ‘Output’ and ‘Input’ from angular. Alternatively, you can use a Service to pass data between components. Check out services and observables.

<parent>
    <app-program-header>
    </app-program-header>
    <app-sidebar>
    </app-sidebar>
</parent>

Upvotes: 2

Related Questions