как интегрировать валидность вложенной формы в основную форму - PullRequest
0 голосов
/ 21 марта 2020

У меня есть компонент A, который выглядит следующим образом

enter image description here

Таким образом, пользователь может создавать различные разделы / ответы и сохранять их , Прямоугольная кнопка angular создается для каждого сохраненного ответа. Внутренне все это сохраняется в формах и проверяется. Я использую ace-editor, который уже предоставляет возможность использовать редактор в качестве элемента управления формой.

фрагмент из A.ts

  createForm() {
    this.codeEditorForm = this.fb.group({
      answer: [null, [this.validateThereIsAtleastOneSavedAnswer(this.answers),this.validateThereIsNoUnsavedAnswer(this.answers)]],
    });
  }

фрагмент из A. html

<ace-editor id="editor" class="form-control" formControlName="answer" [ngClass]="validateField('answer')" [(text)]="text"></ace-editor>

Я хочу использовать этот компонент в качестве элемента управления формой в других компонентах. Например, У меня есть другой компонент B, который также имеет form

B.ts this.bForm = this.fb.group ({field1: [null], field2: [null], field3: [null] , Validators.required], field4: [null], field5: [null], // значение A отображается в это поле формы в B field6: [null]},); }

B. html

<A #a [readonlyFormStatus]="readonlyFormStatus" (answerSectionsEmitter)="handleAEvent($event)" class="form-control" formControlName="field5" [ngClass]="validateField('field5')" ></A>

Я хочу, чтобы, когда bform было отправлено только тогда, когда прошли валидацию bForm и aForm.

Как правильно сделать это, следуя Angular философии дизайна?

1 Ответ

0 голосов
/ 22 марта 2020

Правильный способ, по-видимому, заключается в том, что A реализует интерфейс ControlValueAccessor.

export class A implements OnInit, AfterViewInit,  ControlValueAccessor {
...

...
}

"" * * * SelectControlValueAccessor, который заботится о тексте inputs и textareas, *1009* который обрабатывает select входные данные или CheckboxControlValueAccessor, который, как ни удивительно, имеет дело с checkboxes и т. д. Поэтому для этих элементов пользовательского интерфейса нам не нужно создавать средства доступа к значениям, а для пользовательских компонентов нам нужны создать собственный метод доступа "- https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html

Пояснение - я прошу formB принять значение A и сопоставить его с field5 из formB. Но Angular не знает, каково значение A. Для input полей Angular уже знает, что значение текстового поля - это значение, которое отображается в элемент управления формы. Но для пользовательских компонентов мы должны явно указать Angular, какое значение генерирует пользовательские компоненты, которое сопоставляется с полем form. Это делается путем реализации интерфейса ControlValueAccess.

Интерфейс имеет 3 важных метода. 1) writeValue, который показывает способ изменения пользовательского интерфейса при изменении модели. Скажем, пользовательский интерфейс пользовательского компонента представлял собой ползунок с левым концом, означающим 0%, и правым концом, означающим 100%. Если модель изменит свое значение на 10/100, то пользовательский интерфейс должен опуститься до 10%. Обновите этот метод, чтобы изменить пользовательский интерфейс. В моем случае мне ничего не нужно было делать, потому что направление ввода данных в моем случае - UI для моделирования, а не модель для UI (моя модель не создает текст, который должен быть заполнен в текстовой области.

writeValue(value:any){
    console.log('write value called with value ',value);
  }

2) registerOnChange - это обратное значение writeValue. Всякий раз, когда изменяется пользовательский интерфейс, модель также должна быть изменена. В моем случае, когда пользователь пишет в текстовом поле, я хочу обновить свою модель. «Angular предоставляет вам функцию и просит ее вызывать всякий раз, когда в вашем компоненте изменяется новое значение, чтобы он мог обновить элемент управления». - https://netbasal.com/angular-custom-form-controls-made-easy-4f963341c8e2

В моем случае я хочу распространить изменения, после чего нажимается кнопка сохранения A (тогда вызывается onSaveAnswer). Я хочу распространить значение всех сохраненных ответов в это время

answers:Array<AnswerInformation>;
propagateChange = (_: any) => {};

  registerOnChange(fn) {
    console.log('registerOnchange called');
    this.propagateChange = fn;
  }

  inSaveAnswer(){
...
    this.propagateChange(this.answers);
  }

Полученное значение отображается в поле формы, в которое отображается A.

<A #a [readonlyFormStatus]="readonlyFormStatus" (answerSectionsEmitter)="handleAEvent($event)" class="form-control" formControlName="field5" [ngClass]="validateField('field5')" ></A>

field5 будет содержать предложенные значения (this.answers). его структура будет Array<AnswerInformation>;, т.е. field5:Array<AnswerInformation>;

Я мог бы добавить дополнительную проверку, что field5 не является пустым массивом, как, например, так:

field5: [null, this.validateField5IsProvided]

  validateField5IsProvided(control:AbstractControl) {

      const f5:Array<AnswerInformation> = control.value;
      if(f5){
        if(f5.length !== 0){
          // console.log('answer field is valid');
          return null;
        } else {
          return {
            validateAnswerIsSaved: { // check the class ShowErrorsComponent to see how validatePassword is used.
              valid: false,
              message: 'The field can\'t be empty. Please make sure to save the field'
            }
          };
        }
      } else {
        return {
          validateAnswerIsSaved: { 
            valid: false,
            message: 'The fieldcan\'t be empty. Please make sure to save the field'
          }
        };
      }
    }

Есть еще пара функций, которые требуют также будет реализовано

registerOnTouched() {
    console.log('registerOnTouched called');
  }

  setDisabledState(isDisabled: boolean): void {
    console.log('set disabled called with value ',isDisabled);
    this.editor.setReadOnly(isDisabled);
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...