Как определить, какой элемент в FormArray выпустил событие valueChanges? - PullRequest
0 голосов
/ 06 декабря 2018

В Angular, есть ли способ определить, какой FormGroup / FormControl в динамическом FormArray испустил событие valueChanges?

My FormArray динамичноОн начинается пустым, и пользователи могут добавить FormGroup к FormArray, нажав кнопку.

Когда valueChanges, мне нужно повторно проверить элемент управления.Поскольку я не знаю, какой элемент управления отправил событие, я перебираю весь FormArray и проверяю все FormGroup / FormControl, даже если изменился только один элемент управления - и это каждый раз, когда что-либо в массиве изменяется.Как я могу избежать этого?

        this.myFormArray
        .valueChanges
        .subscribe(data => this.onValueChanged(data));

    onValueChanged(data?: any): void {

    // the data I receive is an entire form array.
    // how can I tell which particular item emitted the event, 
    // so I don’t need to loop through entire array and run validation for all items.

    for (let control in this.myFormArray.controls) {
        // run validation on each control.
    }
}

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Не на моем ПК для тестирования, но, возможно, использование свойства вызывающей функции может направить вас в нужном вам направлении.Хотя это свойство не рекомендуется:

Эта функция не является стандартной и не соответствует стандарту.Не используйте его на рабочих сайтах, выходящих в Интернет: он не будет работать для каждого пользователя.Также могут быть большие несовместимости между реализациями, и поведение может измениться в будущем.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

пример:

this.myFormArray
    .valueChanges
    .subscribe(onValueChanged);

onValueChanged(data?: any): void {
     var whoYouGonnaCall = onValueChanged.caller.caller...caller;
     ...
}

Обновление

Другой вариант - сохранить последнее значение формы и использовать что-то вроде lodash для сравнения свойств.

var lastFormValue = this.myFormArray.value; // maybe in an init function
this.myFormArray
    .valueChanges
    .subscribe(onValueChanged);

onValueChanged(data?: any): void {
     var diff = _.omitBy(data, function(v, k) {
         return lastFormValue[k] === v;
     });
     this.lastFormValue = this.myFormArray.value; // Update for future requests
     // diff will contain the properties if the form that changed.
     ...
}
0 голосов
/ 11 декабря 2018

Я решил эту проблему, добавив formControl (с именем groupIndex) в formGroup для отслеживания индекса и подписавшись на valueChanges на уровне formGroup вместо уровня formArray.На событии valueChanges я мог бы получить доступ к formControl, в котором сохранен текущий индекс.

this.myMainFormGroup = this.myFormBuilder.group({
    // other formControls
    myFormArray: this.myFormBuilder.array([this.addArrayItem()])
});

// this method will be called every time the add button is clicked
addArrayItem(): FormGroup {
  const itemToAdd = this.myFormBuilder.group({
    // dont forget add input control for groupIndex in html for this. It will give error otherwise.
    // i made the input control hidden and readonly
    groupIndex:"", 
    firstName:["", [validator1, validator2]]
    //other formControls

  });

  const myFormArray = <FormArray>this.myMainForm.get("myFormArray");

  //set groupIndex
  itemToAdd.get("groupIndex").patchValue(myFormArray.length -1);

  //subscribe to valueChanges
  itemToAdd.valueChanges
    .debounceTime(200)
    .subscribe(data => this.onValueChanged(data));

  myFormArray.push(itemToAdd);
}

onValueChanged(data?: any): void {
      const groupIndex = data["groupIndex"];

      const myChangedGroup = <FormArray>this.myMainForm.get("myFormArray").controls[groupIndex];

      // now I have hold of the group that changed without having to iterate through the entire array. 
      // run through the custom validator 
      this.generalValidator(myChangedGroup);
    }
0 голосов
/ 06 декабря 2018

Вы можете попробовать что-то вроде этого, но я не уверен, что это будет работать

merge(...this.myFormArray.controls.map(control => control.valueChanges))
  .subscribe(this will be one of your form controls' value);
...