3

I'm new to Angular. I'm trying to access/mutate a variable of a parent component from the child component. I've drawn a small diagram to explain my structure.

  1. Label 1: the parent component where the variable (to be mutated) is situated.
  2. Label 2: the child component which will change parent's variable on click event.
  3. Label 3: the button inside child which will trigger the change.

enter image description here

I have checked many solutions like:

  1. Change parent component state from child component
  2. Angular access parent variable from child component
  3. Angular2: child component access parent class variable/function

But I'm not able to solve my problem. I've created an stackblitz also. Please have a look at my code.

timeselector.component.ts

import { Component, ViewChild } from '@angular/core';
import { MonthpickerComponent } from '../monthpicker/monthpicker.component';

@Component({
    ...
})
export class TimeselectorComponent {

    x : boolean=false;

    @ViewChild('primaryMonthPicker', {static: false}) primaryMonthPicker: MonthpickerComponent;

    recievedFromChild:string="Intentionally left blank";

    GetOutputVal($event) {
        this.recievedFromChild=$event;
    }
}

monthpicker.component.ts

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

@Component({
    ...
})
export class MonthpickerComponent {

  @Output() outputToParent = new EventEmitter<string>();

  constructor() {}

  sendToParent(string:string) {
    this.outputToParent.emit(string);
  }

  buttonClicked() {
    // some logic to access and change timeselector's x
    console.log("Change handler called");
  }

  ngOnInit() {
  }
}

My actual problem is way more complex than this. But I tried to reproduce the same. I just want to see the logic of how it is done, then I'll handle the things my way. I want to change the value of x to true.

An expert told me to create a service. But the project is very complex and I can't make changes to it. It's a team project. Is there any quick fix or less painful solution. Please correct me I'm completely blocked because of this. Here is the stackblitz.

Tanzeel
  • 4,174
  • 13
  • 57
  • 110
  • for your code you have to call `emit` function in your child to get the value emitted from child to parent in the parent ts file , **for example:** in your code you need to call this line `this.outputToParent.emit(string)` inside the click function `buttonClicked()` which called in every click on the button in child template – Ahmed El-sayed Mar 03 '20 at 09:58
  • try this `buttonClicked() {this.sendToParent("string sent from child component");}` – hrdkisback Mar 03 '20 at 10:02
  • I think you forgot to call the sendToParent function – chana Mar 03 '20 at 10:04

5 Answers5

3

Check this out:

https://stackblitz.com/edit/angular-k6fnfk?file=src%2Fapp%2Fmonthpicker%2Fmonthpicker.component.html

You have to pass x to child component, like below:

<app-monthpicker [x]="x" (outputToParent)="GetOutputVal($event)"></app-monthpicker>

Then in your monthpicker (child) component:

  @Input() x;

And to change the x value:

 sendToParent() {
    let newX = this.x + 1;
    this.outputToParent.emit(newX);
  }
BartoszTermena
  • 1,487
  • 1
  • 8
  • 16
  • I'll quickly give this a try. Please give me 5 mins. – Tanzeel Mar 03 '20 at 09:54
  • This is working perfectly. But Sir I'm sorry I made a mistake while framing the question. The variable in real scenario is a `boolean` type which is by default `false`. Can you tell me how to set it to `true` via same mechanism. – Tanzeel Mar 03 '20 at 10:12
  • @Tanzeel sure, check this out: https://stackblitz.com/edit/angular-m6stf7?file=src/app/timeselector/timeselector.component.ts – BartoszTermena Mar 03 '20 at 10:23
  • I've changed my question also. Let me try your new solution. thanks :-) – Tanzeel Mar 03 '20 at 10:25
  • Oh. Now I realized. I already have a `sendToParent` in my code. Which is like this: `sendToParent(string: string) { this.outputToParent.emit(string); }` – Tanzeel Mar 03 '20 at 10:33
  • I tried to accommodate the new boolean value `this.outputToParent.emit(string, newX);` but I'm getting error that only 0-1 args are accepted. what should i do now. :-( – Tanzeel Mar 03 '20 at 10:38
  • Sir, It is already there in the question. See code for **monthpicker.component.ts** – Tanzeel Mar 03 '20 at 10:42
  • Ok, so check out my example based on your code: https://stackblitz.com/edit/angular-m6stf7?file=src%2Fapp%2Fmonthpicker%2Fmonthpicker.component.ts – BartoszTermena Mar 03 '20 at 10:43
  • Sir I tried one more approach. I've posted an alternative answer. :-) – Tanzeel Mar 04 '20 at 05:04
1

On button click(OR any event), you need to emit the value to the parent component using Output decorator.

https://angular.io/guide/component-interaction#parent-listens-for-child-event

I edited your slackblitz, as you were not emiting the output on button click, now it works fine: https://stackblitz.com/edit/angular-zhpbr8

Akshay Rana
  • 1,455
  • 11
  • 20
  • I didn't downvote your answer. In fact I'm reading the links you shared. I appreciate everyone's help. :-) – Tanzeel Mar 03 '20 at 10:07
  • I was asking to whom so ever did. Glad to help. – Akshay Rana Mar 03 '20 at 10:08
  • But my case is different. My `this.outputToParent.emit(string);` is already emitting some string after some logic. Can you please suggest some other way. – Tanzeel Mar 03 '20 at 10:54
  • Is there any other way that I can hit that particular value of parent component. – Tanzeel Mar 03 '20 at 10:55
  • You don't have to emit a string, you can emit an object as well. @Output() outputToParent = new EventEmitter<{x: number, y: string}>(); Instead of providing a type here. It's better to create an Interface. – Akshay Rana Mar 03 '20 at 12:25
  • Ok. And then how to emit this object? Something like this? `sendToParent(string: string) { this.outputToParent.emit({}); }` – Tanzeel Mar 04 '20 at 03:40
1

I've already got my answer. But I tried one more approach. I thought of it by myself. Please tell me to remove this if it is wrong.

Logic: Instead of hitting the value in parent component directly or using sendToparent and this.outputToParent.emit(string);. I created a custom mutator function in the parent component itself which will then change the state of the variable. And I'm simply calling that method from child component.

I took help from:

Angular : calling parent component function from child component

Here's my code:

parent.component.html

<app-child (parentFun)="parentFun()"></app-child>

parent.component.ts

x : boolean=false;
...
parentFun(){
  this.x=true;
}

child.component.html

<button (click)="buttonClicked()">Mutate</button>

child.component.ts

@Output("parentFun") parentFun: EventEmitter<any> = new EventEmitter();
....

buttonClicked() {
  this.parentFun.emit();
}

This is also working for me. With this approach I can do a lot more other changes as well. All my unit test cases are also passing on Jasmine and Karma.

Here's is a working demo: Stackblitz

Tanzeel
  • 4,174
  • 13
  • 57
  • 110
0

Share Data between components in Angular

Check this out, the Child to Parent: Sharing Data via Output() and EventEmitter section

m_sultan
  • 433
  • 5
  • 14
0

Emiting an event using @output and EventEmitter from @angular/core in child component to parent, we can change/modify parent component value by triggering an event from child component.

itzzmeakhi
  • 254
  • 1
  • 2
  • 11