forms - template - validators compose angular 4




자식 구성 요소 및 유효성 검사가있는 각도 2 중첩 된 양식 (4)

children 컴포넌트에 Input을 추가하여 FormGroup을 it.and으로 전달하고 FormGroupName을 사용하여 FormGroup의 이름을 전달할 수 있습니다 :)

children.component.ts

@Input('group');
private dummyGroup: FormGroup;

parent.component.html

<div [formGroup]="userForm" novalidate>
    <div>
        <label>User Id</label>
        <input formControlName="userId">
    </div>
    <div formGroupName="dummy">
        <dummy [group]="userForm.controls['dummy']"></dummy>
    </div>
</div>

각도 2에서 유효성 검사를 통해 중첩 된 양식을 얻으려고합니다. 게시물을보고 문서를 따라했지만 실제로 고민하고 있습니다. 올바른 방향으로 나를 안내 할 수 있기를 바랍니다.

내가 달성하고자하는 것은 여러 자식 구성 요소가있는 유효성이 검사 된 양식을 갖는 것입니다. 이 어린이 구성 요소는 약간 복잡하고 그 중 일부는 더 많은 아동 구성 요소가 있지만 질문을 위해서 부모와 자녀가있는 문제를 공격 할 수 있다고 생각합니다.

내가 성취하려는 것은 무엇인가?

다음과 같이 작동하는 양식이 있습니다.

<div [formGroup]="userForm" novalidate>
    <div>
        <label>User Id</label>
        <input formControlName="userId">
    </div>
    <div>
        <label>Dummy</label>
        <input formControlName="dummyInput">
    </div>
</div>

이렇게하려면 다음과 같은 클래스가 있어야합니다.

private userForm: FormGroup;
constructor(private fb: FormBuilder){
    this.createForm();
}
private createForm(): void{
    this.userForm = this.fb.group({
        userId: ["", Validators.required],
        dummyInput: "", Validators.required]
    });
}

이것은 예상대로 작동하지만 이제는 코드를 분리하고 별도의 다른 구성 요소에 "dummyInput"기능을 넣기를 원합니다. 이것은 내가 잃어버린 곳입니다. 이것은 내가 시도한 것인데, 나는 대답을 얻는데 그리 멀지 않은 것 같지만, 나는 아이디어가 정말 없다. 나는 그 장면에 대해 상당히 새로운 것이다 :

parent.component.html

<div [formGroup]="userForm" novalidate>
    <div>
        <label>User Id</label>
        <input formControlName="userId">
    </div>
    <div>
        <dummy></dummy>
    </div>
</div>

parent.component.ts

private createForm(): void{
    this.userForm = this.fb.group({
    userId: ["", Validators.required],
    dummy: this.fb.group({
        dummyInput: ["", Validators.required]
    })
});

children.component.html

<div [formGroup]="dummyGroup">
    <label>Dummy Input: </label>
    <input formControlName="dummyInput">
</div>

children.component.ts

private dummyGroup: FormGroup;

코드에 맞지 않는 것이 있다는 것을 알고 있지만 실제로는 막막합니다. 도움이 필요합니다.

감사.


거짓말하지 않으려 고, 어떻게이 게시물을 더 일찍 찾지 못했는지 모르겠다.

각도 2 : 하위 구성 요소가 포함 된 양식

해결책은 formGroup을 부모에서 자식으로 Input으로 전달하여 동일한 formGroup에 children 구성 요소를 바인딩하는 것입니다.

문제를 다른 방법으로 해결하기 위해 코드를 공유하는 사람은 기꺼이 받아 들일 것입니다.


주요 개념은 formGroup 및 formControls를 주로 자바 스크립트 객체 및 배열의 ​​변수로 처리해야한다는 것입니다.

그래서 나는 내 요점을 만들기 위해 몇 가지 코드를 넣을 것이다. 아래 코드는 여러분이 가지고있는 것과 다소 비슷합니다. 양식은 동적으로 생성되며, 각 섹션은 필드와 레이블의 공유를 포함하는 섹션으로 분할됩니다.

HTML은 typescript 클래스에 의해 백업됩니다. 그들은 특별한 것이별로 없기 때문에 여기에 있지 않습니다. FormSchemaUI, FormSectionUI 및 FormFieldUI 만 중요합니다.

각 코드를 자체 파일로 취급하십시오.

또한 formSchema : FormSchema 는 서비스에서받는 JSON 객체입니다. 정의되지 않은 UI 클래스의 모든 속성은 기본 Data Clases에서 상속됩니다. 여기에 나와 있지 않습니다. 계층 구조는 다음과 같습니다. FormSchema에는 여러 섹션이 있습니다. 섹션에 여러 입력란이 있습니다.

<form (ngSubmit)="onSubmit()" #ciRegisterForm="ngForm" [formGroup]="formSchemaUI.MainFormGroup">
    <button kendoButton (click)="onSubmit(ciRegisterForm)" [disabled]="!canSubmit()"> Register {{registerPageName}} </button>
    <br /><br />
    <app-ci-register-section *ngFor="let sectionUI of formSchemaUI.SectionsUI" [sectionUI]="sectionUI">
    </app-ci-register-section>
    <button kendoButton (click)="onSubmit(ciRegisterForm)" [disabled]="!canSubmit()"> Register {{registerPageName}} </button>
</form>

=========================================================

<div class="row" [formGroup]="sectionUI.MainFormGroup">
    <div class="col-md-12  col-lg-12" [formGroupName]="sectionUI.SectionDisplayId">
        <fieldset class="section-border">
            <legend class="section-border">{{sectionUI.Title}}</legend>
            <ng-container *ngFor='let fieldUI of sectionUI.FieldsUI; let i=index; let even = even;'>
                <div class="row" *ngIf="even">
                    <ng-container>
                        <div class="col-md-6  col-lg-6" app-ci-field-label-tuple [fieldUI]="fieldUI">

                        </div>
                    </ng-container>
                    <ng-container *ngIf="sectionUI.Fields[i+1]">
                        <div class="col-md-6  col-lg-6" app-ci-field-label-tuple [fieldUI]="sectionUI.FieldsUI[i+1]">

                        </div>
                    </ng-container>
                </div>
            </ng-container>           
        </fieldset>
    </div>
</div>

=========================================================

{{fieldUI.Label}}

=========================================================

<ng-container>
    <div class="row">
        <div class="col-md-4 col-lg-4 text-right">
            <label for="{{fieldUI.FieldDisplayId}}"> {{fieldUI.Label}} </label>
        </div>
        <div class="col-md-8 col-lg-8">
            <div app-ci-field-edit [fieldUI]="fieldUI" ></div>
        </div>
    </div>       
</ng-container>

=========================================================

<ng-container [formGroup]="fieldUI.ParentSectionFormGroup">    
    <ng-container *ngIf="fieldUI.isEnabled">         
        <ng-container [ngSwitch]="fieldUI.ColumnType">            
            <input *ngSwitchCase="'HIDDEN'" type="hidden" id="{{fieldUI.FieldDisplayId}}" [value]="fieldUI.Value" />
            <ci-field-textbox *ngSwitchDefault
                              [fieldUI]="fieldUI"
                              (valueChange)="onValueChange($event)"
                              class="fullWidth" style="width:100%">
            </ci-field-textbox>
        </ng-container>       
    </ng-container>
</ng-container>

=========================================================

export class FormSchemaUI extends FormSchema { 

    SectionsUI: Array<FormSectionUI>;
    MainFormGroup: FormGroup;

    static fromFormSchemaData(formSchema: FormSchema): FormSchemaUI {
        let formSchemaUI = new FormSchemaUI(formSchema);
        formSchemaUI.SectionsUI = new Array<FormSectionUI>();
        formSchemaUI.Sections.forEach(section => {
            let formSectionUI = FormSectionUI.fromFormSectionData(section);

            formSchemaUI.SectionsUI.push(formSectionUI);
        });
        formSchemaUI.MainFormGroup = FormSchemaUI.buildMainFormGroup(formSchemaUI);        
        return formSchemaUI;
    }

    static buildMainFormGroup(formSchemaUI: FormSchemaUI): FormGroup {
        let obj = {};
        formSchemaUI.SectionsUI.forEach(sectionUI => {
            obj[sectionUI.SectionDisplayId] = sectionUI.SectionFormGroup;
        });
        let sectionFormGroup = new FormGroup(obj);
        return sectionFormGroup;
    }
}

=========================================================

export class FormSectionUI extends FormSection {

    constructor(formSection: FormSection) {        
        this.SectionDisplayId = 'section' + this.SectionId.toString();
    }

    SectionDisplayId: string;
    FieldsUI: Array<FormFieldUI>;
    HiddenFieldsUI: Array<FormFieldUI>;
    SectionFormGroup: FormGroup;
    MainFormGroup: FormGroup;
    ParentFormSchemaUI: FormSchemaUI;

    static fromFormSectionData(formSection: FormSection): FormSectionUI {
        let formSectionUI = new FormSectionUI(formSection);
        formSectionUI.FieldsUI = new Array<FormFieldUI>();
        formSectionUI.HiddenFieldsUI = new Array<FormFieldUI>();
        formSectionUI.Fields.forEach(field => {
            let fieldUI = FormFieldUI.fromFormFieldData(field);
            if (fieldUI.ColumnType != 'HIDDEN')
                formSectionUI.FieldsUI.push(fieldUI);
            else formSectionUI.HiddenFieldsUI.push(fieldUI);
        });
        formSectionUI.SectionFormGroup = FormSectionUI.buildFormSectionFormGroup(formSectionUI);
        return formSectionUI;
    }

    static buildFormSectionFormGroup(formSectionUI: FormSectionUI): FormGroup {
        let obj = {};
        formSectionUI.FieldsUI.forEach(fieldUI => {
            obj[fieldUI.FieldDisplayId] = fieldUI.FieldFormControl;
        });
        let sectionFormGroup = new FormGroup(obj);
        return sectionFormGroup;
    }
}

=========================================================

export class FormFieldUI extends FormField {    

    constructor(formField: FormField) {
    super();
    this.FieldDisplayId = 'field' + this.FieldId.toString();       

    this.ListItems = new Array<SelectListItem>();        
   }

    public FieldDisplayId: string;

    public FieldFormControl: FormControl;
    public ParentSectionFormGroup: FormGroup;
    public MainFormGroup: FormGroup;
    public ParentFormSectionUI: FormSectionUI;  

    public ValueChange: EventEmitter<any> = new EventEmitter<any>();    

    static buildFormControl(formFieldUI:FormFieldUI): FormControl {
        let nullValidator = Validators.nullValidator;

        let fieldKey: string = formFieldUI.FieldDisplayId; 
        let fieldValue: any;
        switch (formFieldUI.ColumnType) {            
            default:
                fieldValue = formFieldUI.Value;
                break;
        }
        let isDisabled = !formFieldUI.IsEnabled;
        let validatorsArray: ValidatorFn[] = new Array<ValidatorFn>();
        let asyncValidatorsArray: AsyncValidatorFn[] = new Array<AsyncValidatorFn>();

        let formControl = new FormControl({ value: fieldValue, disabled: isDisabled }, validatorsArray, asyncValidatorsArray);
        return formControl;
    }
}

FormGroupDirective 대한 대안 ( @ blacksheep의 대답에 설명되어 있음)은 ControlContainer 과 같이 사용하는 것입니다.

import { FormGroup, ControlContainer } from "@angular/forms";

export class ChildComponent implements OnInit {

  formGroup: FormGroup;

  constructor(private controlContainer: ControlContainer) {}

  ngOnInit() {
    this.formGroup = <FormGroup>this.controlContainer.control;
  }

formGroup 은 직접 상위 또는 상위 (예 : 상위의 상위)에서 설정할 수 있습니다. 이렇게하면 @Input() 체인을 통해 formGroup을 전달하지 않고도 다양한 중첩 구성 요소에서 from 그룹을 전달할 수 있습니다. 어떤 부모에서라도 formGroup 을 설정하여 자식의 ControlContainer 를 통해 사용할 수 있도록합니다.

<... [formGroup]="myFormGroup">




components