【问题标题】:How to pass data from child component to parent component when button clicked on parent component单击父组件上的按钮时如何将数据从子组件传递到父组件
【发布时间】:2021-01-27 16:18:14
【问题描述】:

当用户单击父组件中存在的提交按钮时,我需要将输入的值从子组件传递到父组件。

childComp 模板

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

childComp TS 文件

export class PasswordInputComponent{

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

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

父组件模板

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

父组件 TS 文件

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

如果按钮存在于子组件中,则很容易 dio。但是在这种情况下,应该在单击父组件中的按钮时传递值!

【问题讨论】:

  • 我不明白。当您从父组件单击 getValueFromChild 时,您想将一个值推送到 tempUserFormPasswords 数组中,但要推送的值来自子组件?

标签: javascript angular parameter-passing angular-event-emitter


【解决方案1】:

在服务文件中创建一个 BehaviorSubject

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

您需要订阅子组件中的数据

密码输入组件

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

当一个按钮点击父组件时我们正在设置数据行为主题,当一个新值添加到它时它会自动订阅子组件。所以,那个时候我们需要发出一个事件。

我想这会对你有所帮助..

【讨论】:

  • 我喜欢这个博客,它解释了从父母到孩子的 4 种沟通方式。你说的这个表格是服务表格。但有时似乎应该更容易fireship.io/lessons/…
【解决方案2】:

对于单个 ChildComponent: 使用ViewChild

对于多个 ChildComponent 使用:ViewChildren

父组件 TS 文件

单子组件:

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

多个子组件:

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

【讨论】:

  • 这似乎只在我在父组件中只导入一次子组件时才有效,如果我多次导入它两次,其他子输入的其他值将是未定义的,我可以知道为什么吗?
  • 如果您需要使用两个或更多组件,则必须使用@ViewChildren,而不是!检查 Angular 文档。
  • 同意@GBra 关于@ViewChildren
  • 你能更新你的答案吗?我会更新问题
  • 当然,等待问题更新,以便更好地反映解决方案
【解决方案3】:

阅读 Angular 中的输入和输出装饰器!
文档:sharing-data
示例:examples

【讨论】:

    【解决方案4】:

    您可以使用 ViewChild 来做到这一点,正如@Raz Ronen 的另一个答案中所述。但请记住,根据 Angular 版本,您可能需要等待 AfterViewInit 生命周期钩子执行才能与子级交互(否则子级将不可用,因为它未初始化)。

    此外,您可以使用 BehaviorSubject 来做到这一点,就像 @Msk Satheesh 刚刚回答的那样,这也很好。但对于这样一个简单的用例,它可能被认为有点过分了。 (这是我们在组件之间没有关系时通常会做的事情,例如一个组件不是另一个组件的子组件)

    我的建议是我认为最简单的(同样,他们的答案无论如何都不错); 它与@Msk Satheesh 基本相同(但在引擎盖下),只是更具 Angular 风格:Output + EventEmitter

    父组件:

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

    子组件:

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

    通过代码,父组件将始终订阅子组件输出的 messageEvent,并在子组件发出后运行函数(消息函数)。使用 Angular 处理这个问题的好处是我们可以确定我们的应用程序中没有任何内存泄漏(例如,缺少取消订阅)。 当正在监听的组件(订阅的父组件)被销毁时,Angular 会自动取消订阅以避免潜在的内存泄漏。

    【讨论】:

    • 感谢您的回答,但这不是我想要的,因为我需要在父组件中单击按钮,就像在单击它时父组件中称为“receiveMessage”的函数一样,它从子组件中获取值
    • 我不确定我是否理解“因为我需要在父组件中单击按钮,就像在单击它时父组件中称为'receiveMessage'的函数一样,它会从子组件中获取值”。所以我不确定我能如何帮助你。我在回答中提到的所有答案都做同样的事情:它们让您可以从孩子到父母共享数据。如果您需要相反的(从父母到孩子),您可以简单地使用input() 而不是output() 并且不使用eventEmitter
    • 我确实需要将数据从子级传递给父级,但在您提供的示例中,您在 childComp 中创建了一个在点击时触发的函数。我想以相同的方式执行此操作,但该按钮存在于父组件中。
    • 您可以使用输入 + 输出和事件发射器来做到这一点。您使用input() 将所需的数据从父母传递给孩子,然后单击您按照示例进行操作。但是,如果您更喜欢使用@viewChild@viewChildren,那就这样做吧。真的一样,只要你的子方法是公开的,就可以从父组件中使用,没有任何问题。
    猜你喜欢
    • 2021-06-11
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 2019-02-27
    • 2017-04-20
    • 2018-03-08
    相关资源
    最近更新 更多