1

I need to pass input's value from child component to parent component when user click on a submit button that exists in parent component.

childComp template

<input 
  type="password" 
  [(ngModel)]="userPasswordForm.inputId"
  class="mr-password-field k-textbox" 
  />

childComp TS file

export class PasswordInputComponent{

    constructor() { }
  
    @Output() inputValue = new EventEmitter<string>();
    userPasswordForm:any={'input':''};

  emitValue(value: string) {
    this.inputValue.emit(value);
  }
}

Parent Component Template

<child-component (inputValue)="" > </child-component>
<button (click)="getValueFromChild()"> </button>

Parent Component TS file

tempUserFormPasswords:any=[];
.
.
.
getValueFromChild(receivedVal){
    this.tempUserFormPasswords.push(receivedVal);
}

It would easy to dio it if the button exists inside the child component. but in this case the value should be passed when the button in the parent component is clicked!

Ali
  • 1,633
  • 7
  • 35
  • 58
  • I do not understand please. You want to push a value into `tempUserFormPasswords` array when you click on `getValueFromChild` from parent but the value to be pushed is coming from the child component? – Michael Ashefor Jan 27 '21 at 16:42

4 Answers4

2

For single ChildComponent: Use ViewChild

For multiple ChildComponent use: ViewChildren

Parent Component TS file

Single Child Component:

tempUserFormPasswords:any=[];
@ViewChild(ChildComponent) child: ChildComponent;
.
.
.
getValueFromChild(receivedVal){
    var data = child.getData();
    this.tempUserFormPasswords.push(data);
}

Multiple Child Component:

tempUserFormPasswords:any=[];
@ViewChildren(ChildComponent) child: ChildComponent;
@ViewChildren(ChildComponent) children: QueryList<ChildComponent>;
.
.
.
getValueFromChild(receivedVal){
    let data;
    children.forEach(child => (data = this.updateData(child.data));
    this.tempUserFormPasswords.push(data);
}
Raz Ronen
  • 2,418
  • 2
  • 14
  • 26
2

Create a BehaviorSubject in service file

@Injectable()
export class dataService {
    data: BehaviorSubject<any> = new BehaviorSubject<any>(null);

    public setData(data: any){
        this.data.next(data);
    }

    public getData(): Observable<any> {
        return this.data.asObservable();
    }
}

You need to subscribe the data in your child component

PasswordInputComponent

export class PasswordInputComponent{

    constructor(private service: dataService) { 
         this.service.getData().subscribe((data) => {
              //Emit the event here
              this.inputValue.emit(value);
         });
    }
  
    @Output() inputValue = new EventEmitter<string>();
    userPasswordForm:any={'input':''};

  emitValue(value: string) {
    this.inputValue.emit(value);
  }
}

ParentComponent.ts

tempUserFormPasswords:any=[];
.
.
.
constructor(private service: dataService) { }
getValueFromChild(receivedVal){
    this.service.setData('');
    this.tempUserFormPasswords.push(receivedVal);
}

When a button clicked on the parent component we are setting the data behaviour subject, when a new value added to that it will automatically subscribed in child component.so, on that time we need to emit a event.

I think this will help you..

Msk Satheesh
  • 1,398
  • 1
  • 6
  • 7
  • I like this blog that explains 4 ways to comunicate from parent to child. This form you say is the service one. But sometimes it seems like it should be easier https://fireship.io/lessons/sharing-data-between-angular-components-four-methods/ – lesolorzanov Oct 12 '21 at 08:41
0

Read about Input and Output decorators in angular!
documentation: sharing-data.
Examples: examples

0

You can do it with ViewChild as already said in the other answer from @Raz Ronen. But keep in mind that depending on the Angular version, you might need to wait for the AfterViewInit lifecycle hook to be executed to interact with the child (or the child won't be available since it's not initialized).

Also, you can do it with a BehaviorSubject, like @Msk Satheesh just answered, and it's perfectly fine too. But it might be considered a bit overkill for such a simple use case. (this is what we usually do when we don't have a relation between the components e.g one component is not children of the other one)

What I suggest is I think the simplest of all (again, their answers are not bad by any means); It is basically the same of @Msk Satheesh (but under the hood), just a bit more Angular styled: Output + EventEmitter:

Parent component:

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

@Component({
  selector: 'app-parent',
  template: `
    Message: {{message}}
    <app-child (messageEvent)="receiveMessage($event)"></app-child>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  constructor() { }

  message:string;

  receiveMessage($event) {
    this.message = $event
  }
}

Children Component:

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

@Component({
  selector: 'app-child',
  template: `
      <button (click)="sendMessage()">Send Message</button>
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  message: string = "a string from child component"

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

  constructor() { }

  sendMessage() {
    this.messageEvent.emit(this.message)
  }
}

With the code, the parent will always be subscribed to the messageEvent that’s outputted by the child component, and it will run the function (the message function) after the child emits. Handling this with Angular has the advantage that we are sure that we don't have any memory leak in our app (e.g missing unsubscriptions). When the component that is listening (the subscribed parent) gets destroyed, Angular will unsubscribe automatically to avoid potential memory leaks.

GBra 4.669
  • 1,512
  • 3
  • 11
  • 23
  • 1
    Thank you for your answer, but this is not the case I want, as i need the button to be clicked in the parent component like a function in the parent component called "receiveMessage" when click it, it gets the value form the child component – Ali Jan 27 '21 at 16:58
  • I am not sure I understand "as i need the button to be clicked in the parent component like a function in the parent component called 'receiveMessage' when click it, it gets the value form the child component". So I am not sure how I can help you. All the answers that I mentioned in my answer do the same thing: they let you share data from child to parent. If you need the opposite (from parent to child) you can simply use `input()` instead of `output()` and without the `eventEmitter`. – GBra 4.669 Jan 27 '21 at 17:17
  • I do need to pass data from child to parent, but in the example you provided, you make a fucntion in the childComp that triggered on click. I want to do it the same way but the button exists in the parent component. – Ali Jan 27 '21 at 17:20
  • you can do so with input + output and event emitter. you pass the required data from parent to child with `input()`, then on click you follow the example. But if you prefer doing it with `@viewChild` or `@viewChildren`, just do it that way. It's really the same, as long as your children methods are public, they can be used from the parent component without any issue. – GBra 4.669 Jan 27 '21 at 17:30