Как передавать данные из дочернего компонента в родительский компонент при нажатии кнопки на родительском компоненте

#javascript #angular #parameter-passing #angular-event-emitter

#javascript #angular #передача параметров #angular-event-эмиттер

Вопрос:

Мне нужно передать значение ввода из дочернего компонента в родительский компонент, когда пользователь нажимает кнопку отправки, которая существует в родительском компоненте.

Шаблон дочернего компонента

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

Файл 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);
}
 

Это было бы легко сделать, если кнопка существует внутри дочернего компонента. но в этом случае значение должно передаваться при нажатии кнопки в родительском компоненте!

Комментарии:

1. Я не понимаю, пожалуйста. Вы хотите поместить значение в tempUserFormPasswords массив при нажатии на getValueFromChild родительский компонент, но передаваемое значение поступает из дочернего компонента?

Ответ №1:

Для одного дочернего компонента: используйте ViewChild

Для использования нескольких дочерних компонентов: 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);
}
 

Комментарии:

1. похоже, это работает только тогда, когда я импортирую дочерний компонент только один раз в родительский компонент, если я импортировал его два раза несколько раз, другие значения из других дочерних входных данных были бы неопределенными, могу я знать, почему?

2. если вам нужно использовать два или более компонентов, вы должны использовать @ViewChildren , вместо этого! Проверьте документы Angular.

3. Согласен с @GBra относительно @ViewChildren

4. не могли бы вы обновить свой ответ? и я обновлю вопрос

5. конечно, ожидание обновления вопроса, чтобы оно лучше отражало решение

Ответ №2:

Создайте объект BehaviorSubject в файле service

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

Вам необходимо подписаться на данные в вашем дочернем компоненте

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

Когда кнопка нажата на родительском компоненте, мы устанавливаем субъект поведения данных, когда к нему добавляется новое значение, оно автоматически подписывается на дочерний компонент component.so , в это время нам нужно выдать событие.

Я думаю, это вам поможет..

Комментарии:

1. Мне нравится этот блог, в котором объясняется 4 способа связи от родителя к потомку. Эта форма, которую вы называете служебной. Но иногда кажется, что это должно быть проще fireship.io/lessons /…

Ответ №3:

Читайте о декораторах ввода и вывода в angular!
документация: совместное использование данных.
Примеры: примеры

Ответ №4:

Вы можете сделать это с помощью ViewChild, как уже было сказано в другом ответе от @Raz Ronen. Но имейте в виду, что в зависимости от версии Angular вам может потребоваться дождаться выполнения перехвата жизненного цикла AfterViewInit для взаимодействия с дочерним элементом (или дочерний элемент не будет доступен, поскольку он не инициализирован).

Кроме того, вы можете сделать это с помощью BehaviorSubject , как только что ответил @Msk Satheesh , и это тоже прекрасно. Но это может показаться немного излишним для такого простого варианта использования. (это то, что мы обычно делаем, когда у нас нет связи между компонентами, например, один компонент не является дочерним элементом другого)

То, что я предлагаю, я считаю самым простым из всех (опять же, их ответы ни в коем случае не плохие); Это в основном то же самое, что и @Msk Satheesh (но под капотом), только немного более угловатый стиль: 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 автоматически откажется от подписки, чтобы избежать потенциальных утечек памяти.

Комментарии:

1. Спасибо за ваш ответ, но это не тот случай, который я хочу, так как мне нужно, чтобы кнопка была нажата в родительском компоненте, как функция в родительском компоненте под названием «ReceiveMessage» при нажатии на нее она получает значение из дочернего компонента

2. Я не уверен, что понимаю, «поскольку мне нужно, чтобы кнопка была нажата в родительском компоненте, как функция в родительском компоненте, называемая «ReceiveMessage», при нажатии на нее она получает значение из дочернего компонента». Поэтому я не уверен, чем могу вам помочь. Все ответы, которые я упомянул в своем ответе, делают одно и то же: они позволяют обмениваться данными от дочернего элемента к родительскому. Если вам нужно обратное (от родителя к потомку), вы можете просто использовать input() вместо output() и без eventEmitter .

3. Мне действительно нужно передавать данные от дочернего компонента к родительскому, но в приведенном вами примере вы выполняете функцию в дочернем компоненте, которая срабатывает при нажатии. Я хочу сделать это таким же образом, но кнопка существует в родительском компоненте.

4. вы можете сделать это с помощью ввода вывода и источника событий. вы передаете необходимые данные от родительского компонента к дочернему с input() помощью, затем по щелчку вы следуете примеру. Но если вы предпочитаете делать это с @viewChild помощью или @viewChildren , просто сделайте это таким образом. Это действительно то же самое, пока ваши дочерние методы являются общедоступными, их можно использовать из родительского компонента без каких-либо проблем.