#ViewChild("childRef") childElementRef -- Cannot read properties of undefined - html

I am trying to understand how to use ´#ViewChild´ in an Angular app, so I have created two components: parent (base) and child with the following code:
import { Component, ViewChild, AfterViewInit } from '#angular/core';
#Component({
selector: 'app-base',
templateUrl: './base.component.html',
styleUrls: ['./base.component.css']
})
export class BaseComponent implements AfterViewInit {
#ViewChild("childRef") childElementRef: any;
childComponentTitle = 'fake child component title';
constructor(public router: Router) { }
ngAfterViewInit(): void {
this.childComponentTitle = this.childElementRef.childComponentTitle;
}
changeChildComponentTitle() {
this.childElementRef.changeComponentState('actual child component title');
}
}
<h1>parent (base) component</h1>
<app-child #childRef></app-child>
<h2>{{ childComponentTitle }}</h2>
<button (click)="changeChildComponentTitle()">Show Real Child Component Title</button>
import { Component } from '#angular/core';
#Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent {
childComponentTitle: string = "";
changeComponentState(newState: string) {
this.childComponentTitle = newState;
}
}
<h1>child component</h1>
<h2>{{ childComponentTitle }}</h2>
If I understand it correctly, once I click the button (which is managed by the ´BaseComponent´) it should invoke the ´changeComponentState´ method (which is managed by the ´ChildComponent´) and that should display ´actual child component title´ on the page.
This does happen, but upon the app loading, I immediately get this error:
ERROR TypeError: Cannot read properties of undefined (reading 'childComponentTitle') at PageoneComponent.ngAfterViewInit
Could someone please help me figure out why this error is thrown?

You should add an if before trying accessing to the child :
ngAfterViewInit(): void {
if (this.childElementRef) {
this.childComponentTitle = this.childElementRef.childComponentTitle;
}
}

Related

Angular: How to send string values to another component using EventEmitter?

I have a parent component and a child component, I want to send 2 values from the child component via EventEmitter to the parent component as I want to use the printMessages() function there.
I have a click event on the child component which emits 2 string values, but I'm unsure how to connect the emit event to the parent component and for the printMessages() function to run. How can the parent component read these values into the "printMessages()" function and for that function to run after the values have reached it? As you can see, I currently have no HTML in the parent component, perhaps I need to do something there?
Parent Component:
import { Component } from '#angular/core';
#Component({
selector: 'parent-component',
template: ``,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
// Function in which I want to send values from the child component.
printMessages(string1: string, string2: string) {
console.log(string1, string2);
}
Child Component:
import { Component, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'child-component',
template: `
<button (click)="sendStrings()">Send Strings</button>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
#Output() message = new EventEmitter();
constructor() { }
sendStrings(){
this.message.emit({string1:"Hello", string2:"World!"});
}
}
You need to react on the child components event within the template and call the method.
import { Component } from '#angular/core';
#Component({
selector: 'parent-component',
template: `<child-component (onMessage)="printMessages(e)"></child-component>`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent {
constructor() { }
printMessages(event) {
// strings are included in event object
}
}

Cannot access the parent formControl object changes in a Parent-Child Component relationship in Angular 8

I have created a parent component as follows:
<form [formGroup] = "cardForm">
<app-inputvalidator [controls] = "cardForm.get('name')"></app-inputvalidator>
</form>
Parent ts file
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl,Validators } from '#angular/forms';
#Component({
selector: 'app-card-form',
templateUrl: './card-form.component.html',
styleUrls: ['./card-form.component.css']
})
export class CardFormComponent implements OnInit {
nameFormControl ;
cardForm = new FormGroup({
name: new FormControl('', [Validators.minLength(5),Validators.maxLength(25)])
});
constructor() {
}
ngOnInit(): void {
this.nameFormControl = this.cardForm.get('name');
}
}
I am passing the nameFormControls to the child component and accessing it in the template as well as class as follows:
InputValidator.ts
import { Component, OnInit, Input } from '#angular/core';
import { FormControl} from '#angular/forms';
#Component({
selector: 'app-inputvalidator',
templateUrl: './inputvalidator.component.html',
styleUrls: ['./inputvalidator.component.css']
})
export class InputvalidatorComponent implements OnInit {
#Input() controls: FormControl;
constructor() {
}
ngOnInit(): void {
}
}
Input Validator.html
<input [formControlName] = "controls"
<br>
<div>{{ controls.errors | json}}</div>
The project is compiled successfully with no errors.
I am getting the value of controls.errors to always null.
Why can I not print the object controls.errors using string interpolation as the value in the name input box changes?
you get null becuase you don't put required validator the min,maxLength validators will return an error if there is value and the value is not valid , if the value is null or empty string this will consider a valid
check the validator 👉 source

Component Interaction #Input

I would like a component to send input to another component. Below is the code .ts and .html. of the two components.
Now the problem is that the html page of the parent component also shows the html part of the child component ... I want the component to pass only one string to the child component
Parent.ts
import ...
#Component({
selector: 'app-parent',
templateUrl: './parent.html',
styleUrls: ['./parent.css']
})
export class ParentComponent implements OnInit {
sostegno : string;
constructor() { }
ngOnInit() { }
avvia1() {
this.sostegno = "xxx";
this.router.navigate(['./xxx'], { relativeTo: this.route });
}
avvia2()
this.sostegno = "yyy";
this.router.navigate(['./yyy'], { relativeTo: this.route });
}
}
Parent.html
<div>
...
</div>
<app-child [sostegno]="sostegno"></app-child>
Child.ts
import ...
#Component({
selector: 'app-child',
templateUrl: './child.html',
styleUrls: ['./child.css']
})
export class ChildComponent implements OnInit {
#Input() sostegno : string;
constructor() { }
ngOnInit() {
console.log(this.sostegno);
}
}
There are some changes which you need to make because looking at the code which your currently have it seems incomplete.
You are using this.router without injecting the Router class in your constructor.
You are using this.route without injecting the ActivatedRoute class in your constructor.
To test that your parent > child interaction is working you can remove your param and instead place a test for the html
<app-child [sostegno]="'Test'"></app-child>
This should work for your ngOnInit function which is inside of your child component. If this works all you need to do now is either initialize sostegno in your parent component else your console log inside your child component will not reflect the changes when you call avvia1 or avvia2 inside of your parent class.
Hope this helps!

Angular html nesting

Let's say I have in some upper level class some angular template code that looks like this
<outer-component>
<a></a>
</outer-component>
Where <a> can be any module that extends a certain interface defined elsewhere, is there a way for <outer-component> be able to take <a> or whatever is placed inside the tags and communicate with it specifically be able to listen to functions or bind to variables in a way that is as succinct as the snippet above?
If you want to share data between a parent and a child (hierarchical relationship) you can use EventEmitter to allow the parent to get data from the child.
In the child component:
import { Component, Input, Output, EventEmitter } from 'angular/core';
#Component({
selector: 'app-child',
template: `
<h3>Child</h3>
Say {{message}}
<button (click)="sendMessage()"></button>
´,
styleUrls: ['pathToStyles.css']
})
export class ChildComponent {
message: string = "Hello world";
#Output() messageEvent = new EventEmitter<string>();
constructor() {}
sendMessage() {
this.messageEvent.emit(this.message);
}
}
In the parent component:
import { Component } from '#angular/core';
#Component({
selector: 'app-parent',
template: `
Message: {{message}}
<app-child (messageEvent)="receiveMessage($event)"></app-child>
`,
styleUrls: ['pathToStyles.css']
})
export class ParentComponent {
constructor() { }
message:string;
receiveMessage($event) {
this.message = $event
}
}

Angular 2/4: Can't update child component view

I want to update the value of str which I used in the view of child component from the parent component, by calling the function change() of child component
here is my code.
import { Component } from '#angular/core';
import { ChildComponent } from './child/child.component';
#Component({
selector: 'app-root',
template: `
<h1>parent</h1>
<button (click)="changeChild()">change child</button>
<app-child></app-child>
`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private cc:ChildComponent) {}
changeChild(){
this.cc.change();
}
}
and the child component is:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-child',
template: `
<p>{{str}}</p>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
private str;
constructor() {
this.str = 'initial'
}
change(){
this.str = 'changed'
}
ngOnInit() {
}
}
but the value str in the view never updated to "changed".
please Any help because I am new in Angular 4 ??
Use #ViewChild to get reference of child component
in Parent component
import {ChildComponent} from 'child.component.ts'
export class ParentComponent{
------
#ViewChild(ChildComponent)
private child:ChildComponent
---
changeChild(){
this.child.change()
}
}