2

When I use @ViewChild I get the error that the component is not defined. When I use @ViewChildren I get the error that the function from that component is not a function.

I am new to using child components in Angular so I'm not sure why it's doing this when I do have the child component defined in the parent component and when it's clearly a function in the child component.

I don't want to have to define every function from the child in the parent or else what's even the point of using a separate component.

Child Component

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-mood',
  templateUrl: './mood.component.html',
  styleUrls: ['./mood.component.css']
})
export class MoodComponent implements OnInit {

  moodColors = ['red', 'orange', 'grey', 'yellow', 'green'];

  constructor() { }

  ngOnInit(): void {
  }

  chooseMood() {
    alert(this.moodColors);
  }

}

Parent Component (Relavant Part of Version with "ERROR TypeError: ctx_r3.mood is undefined")

import { Component, OnInit, ViewChild, ViewChildren } from '@angular/core';
import { ViewEncapsulation } from '@angular/core';
import { MoodComponent } from '../mood/mood.component';

@Component({
  selector: 'app-calendar',
  templateUrl: './calendar.component.html',
  styleUrls: ['./calendar.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class CalendarComponent implements OnInit {

  @ViewChild('mood') mood: MoodComponent = new MoodComponent;

Parent Component (Relavant Part of Version with "ERROR TypeError: ctx_r3.mood.chooseMood is not a function")

import { Component, OnInit, ViewChild, ViewChildren } from '@angular/core';
import { ViewEncapsulation } from '@angular/core';
import { MoodComponent } from '../mood/mood.component';

@Component({
  selector: 'app-calendar',
  templateUrl: './calendar.component.html',
  styleUrls: ['./calendar.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class CalendarComponent implements OnInit {

  @ViewChildren('mood') mood: MoodComponent = new MoodComponent;

Parent View

<h2 (click)="mood.chooseMood()"></h2>
Matt
  • 45
  • 5
  • I forgot to add, I can call that child function from the parent view using interpolation so I know it can see it, but I can't use that for what I'm trying to do. – Matt Jan 26 '22 at 04:38

2 Answers2

0

You don't explicitly initialize view children via new.

Just use:

@ViewChild('mood') mood : MoodComponent;

If that doesn't work post a Stackblitz example which I can edit to resolve the issue.

Also, using ViewChild is more of an exception in Angular, and your use of it points to a probable design issue. More likely you child component should emit via an Output to the parent.

Regarding outputs, you can do something like this - though it is hard to give a precise answer without deeper knowledge of what you are trying to achieve:

export class MoodComponent implements OnInit {
 @Input() moodId: string;
 @Output() chooseMood = new EventEmitter<string>();

  moodClicked(){
    this.chooseMood.emit(moodId);
  }
}

export class CalendarComponent implements OnInit {
  moodChosen(string: moodId){
    console.log(moodId);
  }
}

// Calendar template:

<app-mood
  moodId="happy"
  (chooseMood)="moodChosen($event)"
></app-mood>
wlf
  • 3,086
  • 1
  • 19
  • 29
  • I'm not too familiar with output. Would I be able to use any method or variable from that 1 output? – Matt Jan 26 '22 at 17:38
  • also the code snippet you told me to use just gives me an error before compiling "Member 'mood' implicitly has an 'any' type." – Matt Jan 26 '22 at 18:25
  • It's because it has not type and your compiler settings have 'no implicit any' - easy solution is to add the `MoodComponentType` as I have updated above. – wlf Jan 26 '22 at 19:19
  • The Input/Output allowed me to do what I was trying to achieve so I will mark this answer correct. But just to make the answer about how to get past those errors consolidated to this marked answer I will copy and past them to this comment: "Re your 'no initializer' error - see [https://stackoverflow.com/a/50241920/1188074](https://stackoverflow.com/a/50241920/1188074) - you have the default (overly) strict compiler settings which also contribute to the error you are seeing with the 'any' type, though that one is fairly useful to enforce." -[wlf](https://stackoverflow.com/users/1188074/wlf) – Matt Jan 26 '22 at 23:22
0

1 - you have to use this code

@ViewChild('mood') mood : MoodComponent;

when you are using @ViewChildren it will return list of items with the 'mood' name then you have to use this code

mood.first.chooseMood() ;

its better use ViewChildren when there is ngIf in your element

2- no need new keyword for initialize mood variable it would be fill after ngOnInit life cycle fires

  • if I use your first example. I get an error before I can even compile. "Property 'mood' has no initializer and is not definitely assigned in the constructor." – Matt Jan 26 '22 at 18:09
  • And if I use @ViewChild('mood') mood!: MoodComponent; is still says "ctx_r3.mood is undefined" – Matt Jan 26 '22 at 18:21
  • Re your 'no initializer' error - see https://stackoverflow.com/a/50241920/1188074 - you have the default (overly) strict compiler settings which also contribute to the error you are seeing with the 'any' type, though that one is fairly useful to enforce. – wlf Jan 26 '22 at 19:22
  • you can search about "The non-null assertion operator" , and change code like this @ViewChild('mood') mood! : MoodComponent; – Ali Mirzaie Jan 29 '22 at 05:17