Как мы обрабатываем FormArrays и FormGroups с помощью ControlValueAccessor в Angular 14?

Я создаю форму с пользовательскими данными, используяControlValueAccessorкоторый можно посмотреть здесь , на stackblitz, и кажется, что всякий раз, когда он входит в уравнение, все выходит из-под контроля. Я также заметил, что мне нужно использоватьFormControlNameon s, чтобы изменения были обновлены в родительской форме.

Моя общая форма выглядит так

      export class SvgParserComponent implements OnInit{

  SvgForm : FormGroup<SvgForm> = new FormGroup<SvgForm>({
    title: new FormControl<string>(''),
    graphicId: new FormControl<string>(''),
    svgInput: new FormControl<string>(''),
    viewBox: new FormGroup<ViewBoxParams>({
      x: new FormControl<string>(''),
      y: new FormControl<string>(''),
      width: new FormControl<string>(''),
      height: new FormControl<string>('')
    }),
    styling: new FormGroup<StylingParams>({
      globalStyles: new FormControl<string>(''),
      mediaQueries: new FormArray<FormGroup<MediaQueryParams>>([])
    })
  });

  //other code
}

Шаблон для этого уровня формы выглядит так

      <form class="mainGrid" [formGroup]="SvgForm" (ngSubmit)="submitForm()">
  <p>svg parser</p>

  <code-input formControlName="svgInput"></code-input>

  <text-input formControlName="title" [label]="'title'"></text-input>
  
  <text-input formControlName="graphicId" [label]="'graphic id'"></text-input>

  <viewbox-input formControlName="viewBox"></viewbox-input>

  <styling-input formGroupName="styling"></styling-input>

  <button type="submit">submit</button>
</form>

Если вы посмотрите наviewbox-inputвы увидите, что у меня есть этот набор с, а не потому, что введенные значения не будут обновляться в родительском компоненте в противном случае. Однако это создает проблемы, если я устанавливаю его, поэтому я просто оставил его как .

Внутри есть a, который повторяет a, в котором есть FormsGroups и FormArrays. У меня настроено так.

      @Component({
  selector: 'styling-input',
  templateUrl: './styling-input.component.html',
  styleUrls: ['./styling-input.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: StylingInputComponent,
      multi: true
    }
  ]
})
export class StylingInputComponent implements ControlValueAccessor{

  StylingForm: FormGroup<StylingParams> = new FormGroup<StylingParams>({
    globalStyles: new FormControl<string>(''),
    mediaQueries: new FormArray<FormGroup<MediaQueryParams>>([])
  });

  get MediaQueryList() {
    return this.StylingForm.get('mediaQueries') as FormArray<FormGroup<MediaQueryParams>>;
  }

  writeValue(value: any){ if(value){ this.StylingForm.setValue(value); } }

  registerOnChange(fn: any){ this.StylingForm.valueChanges.subscribe(fn); }

  registerOnTouched(onTouched: Function){}

  private createMediaQueryGroup(): FormGroup<MediaQueryParams> {

    return new FormGroup<MediaQueryParams>({
      selectorParams: new FormGroup<MediaSelectorParams>({
        mediaType: new FormControl<MediaTypeParams>('all'),
        expressions: new FormArray<FormGroup<MediaExpressionGroupParams>>([]),
      }),
      rules: new FormControl<string>('')
    });
  }

  public addMediaQuery():void{
    this.MediaQueryList.push(this.createMediaQueryGroup());
  }

  public removeMediaQuery(item: number): void{
    this.MediaQueryList.removeAt(item);
  }

}

и шаблон для этого компонента выглядит так

      <article [formGroup]="StylingForm">
  <p>Styles</p>

  <code-input formControlName="globalStyles"></code-input>

  <section>
    <article formArrayName="MediaQueryList">

      <media-query-input *ngFor="let a of MediaQueryList.controls; let i = index"
        [formGroupName]="i"
        [attr.GroupId]="i"
        (RemoveGroup)="removeMediaQuery($any($event))"
      ></media-query-input>

    </article>

    <article>
      <button type="button" (click)="addMediaQuery()">add media query</button>
    </article>
  </section>

</article>

Итак, внутри этого шаблона у меня естьcode-inputчто такое и что такоеFormGroupкоторый повторяется из . На данный момент я получаю следующие ошибки

control.registerOnChange не является функцией

Не удается найти элемент управления с именем: «MediaQueryList»

затем, когда я нажимаюadd media queryкнопка отображает другой компонент, и появляется эта ошибка

Не удается найти элемент управления с путем: «MediaQueryList -> 0»

Внутри у меня есть еще одинFormControlиFormArrayэто выглядит странно, показывая, что что-то явно не так, и я предполагаю, что это просто рекурсия той же проблемы, с которой я сталкиваюсь вstyling-inputс правильной итерацией и рендерингомmedia-query-input.

я пытался переключитьсяformGroupNameдляformControlNameи даже пытался[attr.formControlName]в некоторых местах я добавилforwardRef(()=> Component)кuseExistingсобственность в моемprovidersчто привело к ошибкам, сообщающим мне, что элементы управления и группы еще не существовали. Как я должен структурировать это, чтобы все работало?

0 ответов

Другие вопросы по тегам