Отключенные элементы управления из FormGroup (часть пользовательского элемента управления формы) исключаются .getRawValue () в родительском элементе - PullRequest
0 голосов
/ 13 января 2019

Наличие компонента, который реализует ControlValueAccessor, с внутренним FormGroup для поддержания состояния пользовательского элемента управления формы. Когда какое-либо поле, являющееся частью этого FormGroup, отключено, оно не отображается при вызове метода .getRawValue() в родительской форме.

По спецификации, .getRawValue() должен возвращать необработанный объект, включая отключенные поля.

Я проверил код .getRawValue() и вот что я нашел:

 getRawValue(): any {
    return this._reduceChildren(
        {}, (acc: {[k: string]: AbstractControl}, control: AbstractControl, name: string) => {
          acc[name] = control instanceof FormControl ? control.value : (<any>control).getRawValue();
          return acc;
        });
  }

Таким образом, в основном, когда элемент управления формой является экземпляром FormControl (это верно при использовании пользовательских элементов управления формы, верно?), Он получает .value вместо .getRawValue(), и поэтому отключенные элементы управления вложенной формы не включен в конечном объекте.

Демонстрация Stackblitz

Шаги для воспроизведения:

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

2) Изучите выходные данные ниже => .getRawValue() и .value ответы идентичны.

Ты хоть представляешь, как мне это преодолеть? Я ищу способ получения отключенных элементов управления также в родительской форме.

1 Ответ

0 голосов
/ 13 января 2019

Kav, в вашем пользовательском контроле формы есть

  registerOnChange(fn: (v: any) => void) {
        this.formGroup.valueChanges.subscribe(fn);
    }

Итак, ваш компонент возвращает «значение» formGroup. Поскольку элемент управления отключен, значение не возвращает это поле. Вы можете изменить свой customControl, чтобы он возвращал rawValue формы formGroup, для этого вам нужно создать функцию onChangeFunction, а в ngOnInit подписаться на изменения и отправить rawValues. Когда мы подписываемся, хорошо отписаться, используя takeWhile и переменную

export class DetailsFields implements ControlValueAccessor,OnInit,OnDestroy {
    ...
    onChange: (v:any) => void = () => {}; //<--define a function
    isAlive:boolean=true; //<--use to unsubscribe, see below

    registerOnChange(fn: (v: any) => void) {
      this.onChange = fn; //<--equal to function
    }

    //In ngOnInit
    ngOnInit()
    {
      this.formGroup.valueChanges.pipe(takeWhile(()=>this.isAlive))
        .subscribe(v=>{
        //return this.formGroup.getRawValue()
        this.onChange(this.formGroup.getRawValue())
      })
    }
    //In ngOnDestroy
    ngOnDestroy() {  //make isAlive=False to unsubscribe
      this.isAlive=false;
    }

Но в этом случае вы получили год, всегда включен или нет

Существует еще один подход, в котором нет настраиваемого элемента управления формой, а просто компонент для управления маркой, годом и цветом. Для этого, во-первых, измените ваш компонент приложения и создайте форму как другую форму с formArray.

<div id="cars" [formGroup]="form">
  <div formArrayName="cars">
  <div *ngFor="let car of form.get('cars').controls; let i = index;" 
   [formGroupName]="i">
    <app-details-fields [formGroup]="form.get('cars').at(i)" ></app-details-fields>
  </div>
  </div>
</div>

Обратите внимание, что в formArray мы перебираем элементы управления form.get ('cars'). В компонент просто передайте в качестве ввода [formGroup] form.get ('cars'). At (i)

Конечно, вам нужно изменить функцию "createCars", чтобы она возвращала formGroup. не formControl, который возвращает тип объекта {make: .., color: .., year}

createCar(car: any) {  //return a formGroup,not a formControl
    return this.builder.group({
      make: car.make,
      color: car.color,
      year: car.year
    });
  }

Ну, подробные поля становятся проще:

подробности-fields.component.ts

@Component({
  selector: 'app-details-fields',
  templateUrl: './details-fields.component.html',
  styleUrls: ['./details-fields.component.css']  ,
})

export class DetailsFields {
   @Input() formGroup:FormGroup

   disableYear() {
      this.formGroup.get('year').disable();
    }

    enableYear() {
      this.formGroup.get('year').enable();
    }
}

подробности-fields.component.html

<div [formGroup]="formGroup">
  <div class="car-wrap">
      <div>
          <p class="title">This car is a {{formGroup.get('make').value}}</p>
      <div>
        <input type="text" formControlName="make">
        <input type="number" formControlName="year">
        <input type="text" formControlName="color">
      </div>
      <div>
        <button style="margin-top: 3px;" (click)="enableYear()">Enable year</button>
        <button style="margin-top: 3px;" (click)="disableYear()">Disable year</button>
      </div>
    </div>
  </div>
</div>
...