简体   繁体   中英

How to pass data from child component to parent component when button clicked on parent component

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!

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);
}

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..

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

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 eg 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 (eg missing unsubscriptions). When the component that is listening (the subscribed parent) gets destroyed, Angular will unsubscribe automatically to avoid potential memory leaks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM