source

Angular Reactive Forms: 확인란 값 배열을 생성합니까?

manysource 2023. 5. 20. 10:55

Angular Reactive Forms: 확인란 값 배열을 생성합니까?

한 일한항에에 됩니다.formControlName음에바된확인값배생열어해합니까야떻에 확인란 값 하려면 어떻게 ?formControl단순한 것이 아니라true/false?

예:

<form [formGroup]="checkboxGroup">
    <input type="checkbox" id="checkbox-1" value="value-1" formControlName="myValues" />
    <input type="checkbox" id="checkbox-2" value="value-2" formControlName="myValues" />
    <input type="checkbox" id="checkbox-3" value="value-2" formControlName="myValues" />
</form>

checkboxGroup.controls['myValues'].value현재 생산되는 제품:

true or false

내가 원하는 것은 다음과 같습니다.

['value-1', 'value-2', ...]

조용한 답변의 도움으로, 저는 제 양식 Builder에서 상태 대신 가치를 얻을 수 있는 솔루션을 작성했습니다.

나는 배열 형식에서 값을 추가하거나 제거하는 방법을 사용합니다.그것은 나쁜 접근법일 수도 있지만, 효과가 있습니다!

구성요소.구성요소

<div *ngFor="let choice of checks; let i=index" class="col-md-2">
  <label>
    <input type="checkbox" [value]="choice.value" (change)="onCheckChange($event)">
    {{choice.description}}
  </label>
</div>

구성 요소.ts

// For example, an array of choices
public checks: Array<ChoiceClass> = [
  {description: 'descr1', value: 'value1'},
  {description: "descr2", value: 'value2'},
  {description: "descr3", value: 'value3'}
];

initModelForm(): FormGroup{
  return this._fb.group({
    otherControls: [''],
    // The formArray, empty 
    myChoices: new FormArray([]),
  }
}

onCheckChange(event) {
  const formArray: FormArray = this.myForm.get('myChoices') as FormArray;

  /* Selected */
  if(event.target.checked){
    // Add a new control in the arrayForm
    formArray.push(new FormControl(event.target.value));
  }
  /* unselected */
  else{
    // find the unselected element
    let i: number = 0;

    formArray.controls.forEach((ctrl: FormControl) => {
      if(ctrl.value == event.target.value) {
        // Remove the unselected element from the arrayForm
        formArray.removeAt(i);
        return;
      }

      i++;
    });
  }
}

예를 들어 양식을 제출할 때 모델은 다음과 같습니다.

  otherControls : "foo",
  myChoices : ['value1', 'value2']

모델에 이미 확인된 값이 있는 경우 formArray를 채우는 함수 하나만 누락되었습니다.

여기에 사용하기 좋은 장소가 있습니다.FormArray https://angular.io/docs/ts/latest/api/forms/index/.htmlhttps ://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html

시작하기 위해 다음 중 하나를 사용하여 제어 장치를 구성합니다.FormBuilder아니면 새로 시작하는 것.FormArray

양식 작성기

this.checkboxGroup = _fb.group({
  myValues: _fb.array([true, false, true])
});

새 양식 배열

let checkboxArray = new FormArray([
  new FormControl(true),
  new FormControl(false),
  new FormControl(true)]);

this.checkboxGroup = _fb.group({
  myValues: checkboxArray
});

쉽게 할 수 있지만 템플릿을 변경하여 템플릿 엔진이 컨트롤에 바인딩하는 방법을 처리하도록 할 것입니다.

template.vmdk

<form [formGroup]="checkboxGroup">
    <input *ngFor="let control of checkboxGroup.controls['myValues'].controls"
    type="checkbox" id="checkbox-1" value="value-1" [formControl]="control" />     
  </form>

여기서 우리는 우리의 세트에 대해 반복하고 있습니다.FormControls우리들 안에서myValues FormArray그리고 각 통제 장치에 대해 우리는 구속합니다.[formControl]대신에 그 통제에.FormArray 및 어및제<div>{{checkboxGroup.controls['myValues'].value}}</div>true,false,true템플릿 구문을 약간 덜 수동으로 만드는 동안.

다음 예를 사용할 수 있습니다. http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview 에서 검색할 수 있습니다.

확인란 정보가 API에서 비동기식으로 채워지는 경우에도 이전 버전보다 Angular 6에서 이 작업을 훨씬 쉽게 수행할 수 있습니다.

가장 먼저 깨달아야 할 것은 Angular 6의 덕분입니다.keyvalue가 없는 우가사용필요없는파프이가리할▁we▁pipe프파.FormArray더 이상, 그리고 대신 둥지를 틀 수 있습니다.FormGroup.

먼저 FormBuilder를 생성자에게 전달합니다.

constructor(
    private _formBuilder: FormBuilder,
) { }

그런 다음 양식을 초기화합니다.

ngOnInit() {

    this.form = this._formBuilder.group({
        'checkboxes': this._formBuilder.group({}),
    });

}

확인란 옵션 데이터를 사용할 수 있으면 데이터를 반복하고 중첩된 데이터로 직접 밀어넣을 수 있습니다.FormGroup이 붙은 명으로로서.FormControl인덱스된 검색 배열 수에 의존할 필요가 없습니다.

const checkboxes = <FormGroup>this.form.get('checkboxes');
options.forEach((option: any) => {
    checkboxes.addControl(option.title, new FormControl(true));
});

마지막으로, 템플릿에서 우리는 단지 반복하기만 하면 됩니다.keyvalue: 없음: 추가 확인란let index = i그러면 확인란이 자동으로 알파벳 순으로 훨씬 깨끗해집니다.

<form [formGroup]="form">

    <h3>Options</h3>

    <div formGroupName="checkboxes">

        <ul>
            <li *ngFor="let item of form.get('checkboxes').value | keyvalue">
                <label>
                    <input type="checkbox" [formControlName]="item.key" [value]="item.value" /> {{ item.key }}
                </label>
            </li>
        </ul>

    </div>

</form>

저는 반응형을 최대한 사용하여 질문에 완전히 답할 수 있는 해결책을 찾지 못했기 때문에 여기 동일한 해결책이 있습니다.


요약

StackBlizz의 예와 함께 자세한 설명의 요점은 다음과 같습니다.

  1. 사용하다FormArray확인란을 선택하고 양식을 초기화합니다.
  2. valueChanges관찰 가능한 항목은 양식에 표시되지만 구성요소에 다른 항목을 저장하려는 경우에 적합합니다.을 .true/false값을 여기서 원하는 값으로 설정합니다.
  3. 다니합거를 .false제출 시점의 값입니다.
  4. 구독에서 구독 valueChanges관측할 수 있는

StackBlizz 예제


상세설명

FormArray를 사용하여 양식 정의

정답으로 표시된 답변에서 이미 언급한 것처럼. FormArray데이터를 배열로 가져오는 것을 선호하는 경우에 사용하는 방법입니다.그래서 가장 먼저 해야 할 일은 양식을 만드는 것입니다.

checkboxGroup: FormGroup;
checkboxes = [{
    name: 'Value 1',
    value: 'value-1'
}, {
    name: 'Value 2',
    value: 'value-2'
}];

this.checkboxGroup = this.fb.group({
    checkboxes: this.fb.array(this.checkboxes.map(x => false))
});

이 이게하모확든인초기의값이설다다정니됩로음으로 설정됩니다.false.

양식 를 템플릿에 하고 다으로음, ▁overerate▁and▁in▁next▁variables▁template▁we▁register▁form▁to다합니▁it,▁need▁these▁the반야복해다통해음,로에 반복해야 합니다.checkboxes배열(해당되지 않음)FormArray그러나 확인란 데이터)를 선택하여 템플릿에 표시합니다.

<form [formGroup]="checkboxGroup">
    <ng-container *ngFor="let checkbox of checkboxes; let i = index" formArrayName="checkboxes">
        <input type="checkbox" [formControlName]="i" />{{checkbox.name}}
    </ng-container>
</form>

Changes를 관찰할 수 있는 값을 사용합니다.

여기 주어진 어떤 답변에서도 언급되지 않은 부분이 있습니다.이러한 상황에서, 우리는 언급된 데이터를 표시하지만 그것을 다른 것으로 저장하고 싶습니다.valueChanges관찰 가능한 것은 매우 도움이 됩니다.용사를 합니다.valueChanges는 우는변화수있다니습의 할 수 있습니다.checkboxes그리고 나서.map그자리의 true/false에서 받은 값FormArray원하는 데이터로.확인란에 전달된 값은 확인란에 선택된 것으로 표시되고 그 반대의 경우도 마찬가지이므로 확인란의 선택은 변경되지 않습니다.

subscription: Subscription;

const checkboxControl = (this.checkboxGroup.controls.checkboxes as FormArray);
this.subscription = checkboxControl.valueChanges.subscribe(checkbox => {
    checkboxControl.setValue(
        checkboxControl.value.map((value, i) => value ? this.checkboxes[i].value : false),
        { emitEvent: false }
    );
});

으로 이은기로매다니핑됩으를 .FormArray 원에대 가관치에 값checkboxes하고 array를 합니다.value에 " 란이표경우된시로확인경우▁as"로 표시된 true그렇지 않으면 그것은 돌아옵니다.false.emitEvent: false여기서 중요한 것은 다음을 설정하기 때문입니다.FormArray그것이 없는 가치는 야기할 것입니다.valueChanges무한 루프를 생성하는 이벤트를 내보냅니다.emitEventfalse우리는 확실히 하고 있습니다.valueChanges여기서 값을 설정할 때 관측 가능한 값은 방출되지 않습니다.

잘못된 값을 필터링

는 직필터할수다니없을 직접 수 .falseFormArray확인란에 바인딩되어 있기 때문에 템플릿이 엉망이 됩니다.따라서 가능한 최선의 해결책은 다음을 걸러내는 것입니다.false값을 입력합니다.스프레드 연산자를 사용하여 이 작업을 수행합니다.

submit() {
    const checkboxControl = (this.checkboxGroup.controls.checkboxes as FormArray);
    const formValue = {
        ...this.checkboxGroup.value,
        checkboxes: checkboxControl.value.filter(value => !!value)
    }
    // Submit formValue here instead of this.checkboxGroup.value as it contains the filtered data
}

이것은 기본적으로 잘못된 값을 걸러냅니다.checkboxes.

valueChanges 가입 취소

을 취소하는 valueChanges

ngOnDestroy() {
    this.subscription.unsubscribe();
}

참고: 값을 설정할 수 없는 특별한 경우가 있습니다.FormArrayvalueChanges 값이 예: 확란값숫설자정경우된로이인으로 0확인란을 선택하면 다음과 같이 설정되므로 확인란을 선택할 수 없습니다.FormControl0(허위 값)을 선택하지 않은 상태로 유지합니다.번호를 사용하지 않는 것이 좋습니다.0에는 조건부로 .0어 진 한 값 로 으 실 고 합 라 이 니 다 열 문 자 떤 합 ▁string 다 니 ▁to , ▁say 고 라 이문 ▁some ▁tr ut'0'아니면 그냥 평범함.true때 다시 로 변환합니다.0.

StackBlizz 예제

또한 StackBlizz에는 기본값을 확인란에 전달하여 UI에서 확인란으로 표시할 수 있는 코드가 있습니다.

TL;DR

  1. FormGroup을 사용하여 확인란 목록을 채우는 것을 선호합니다.
  2. 하나 이상의 확인란이 선택되었는지 확인하기 위한 사용자 지정 검증자 작성
  3. 작업 예제 https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

이는 때때로 인상적이어서 FormArray 및 FormGroup 접근 방식을 모두 사용해 보았습니다.

대부분의 경우 서버에 체크박스 목록이 채워졌고 API를 통해 받았습니다.그러나 미리 정의된 값을 가진 정적 확인란 집합이 나타날 수 있습니다.각 사용 사례에서 해당 FormArray 또는 FormGroup이 사용됩니다.

으로 기적으로.FormArray는 의변니다의 입니다.FormGroup중요한 차이점은 데이터가 어레이로 직렬화된다는 것입니다(FormGroup의 경우 개체로 직렬화되는 것과 달리).이 기능은 동적 양식과 같이 그룹 내에 얼마나 많은 컨트롤이 있는지 모를 때 특히 유용할 수 있습니다.

단순성을 위해, 당신이 단순한 제품 양식을 가지고 있다고 상상해 보십시오.

  • 필수 제품 이름 텍스트 상자 하나.
  • 선택할 범주 목록입니다. 하나 이상의 범주를 선택해야 합니다.서버에서 목록을 검색한다고 가정합니다.

먼저 제품명만 기재된 양식을 설정합니다.formControl필수 필드입니다.

this.form = this.formBuilder.group({
    name: ["", Validators.required]
});

카테고리가 동적으로 렌더링되므로 데이터가 준비된 후 나중에 양식에 이 데이터를 추가해야 합니다.

this.getCategories().subscribe(categories => {
    this.form.addControl("categoriesFormArr", this.buildCategoryFormArr(categories));
    this.form.addControl("categoriesFormGroup", this.buildCategoryFormGroup(categories));
})

범주 목록을 구성하는 두 가지 방법이 있습니다.

양식 배열

  buildCategoryFormArr(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormArray {
    const controlArr = categories.map(category => {
      let isSelected = selectedCategoryIds.some(id => id === category.id);
      return this.formBuilder.control(isSelected);
    })
    return this.formBuilder.array(controlArr, atLeastOneCheckboxCheckedValidator())
  }
<div *ngFor="let control of categoriesFormArr?.controls; let i = index" class="checkbox">
  <label><input type="checkbox" [formControl]="control" />
    {{ categories[i]?.title }}
  </label>
</div>

것이.buildCategoryFormGroupFormArray 반 합니다환.또한 선택한 값의 목록을 인수로 사용하므로 양식을 데이터 편집에 다시 사용하려는 경우 유용할 수 있습니다.새 제품 양식을 만들 때는 아직 적용되지 않습니다.

formArray 값에 액세스하려고 할 때 참고합니다.은 보것입다니일처처럼 입니다.[false, true, true]선택한 ID 목록을 가져오려면 목록에서 확인해야 하지만 배열 인덱스를 기반으로 하는 작업이 조금 더 필요했습니다.듣기에는 좋지 않지만 효과가 있습니다.

get categoriesFormArraySelectedIds(): string[] {
  return this.categories
  .filter((cat, catIdx) => this.categoriesFormArr.controls.some((control, controlIdx) => catIdx === controlIdx && control.value))
  .map(cat => cat.id);
}

그래서 제가 이걸 사용하게 된 거예요.FormGroup 점에 관해서는

양식 그룹

formGroup폼 데이터를 개체로 저장합니다. 이 개체에는 폼 컨트롤에 대한 키 맵이 필요합니다.를 따서키키설로것정좋이습다니는하를라▁the▁as▁the▁key다로 설정하는 것이 .categoryId나중에 회수할 수 있습니다.

buildCategoryFormGroup(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormGroup {
  let group = this.formBuilder.group({}, {
    validators: atLeastOneCheckboxCheckedValidator()
  });
  categories.forEach(category => {
    let isSelected = selectedCategoryIds.some(id => id === category.id);
    group.addControl(category.id, this.formBuilder.control(isSelected));
  })
  return group;
}
<div *ngFor="let item of categories; let i = index" class="checkbox">
  <label><input type="checkbox" [formControl]="categoriesFormGroup?.controls[item.id]" /> {{ categories[i]?.title }}
  </label>
</div>

양식 그룹의 값은 다음과 같습니다.

{
    "category1": false,
    "category2": true,
    "category3": true,
}

하지만 대부분의 경우, 우리는 단지 목록만 얻기를 원합니다.categoryIds~하듯이["category2", "category3"]저는 또한 이 자료들을 가져가기 위해 get을 써야 합니다.formArray에 비해 이 접근 방식이 더 마음에 듭니다. 폼 자체에서 가치를 얻을 수 있었기 때문입니다.

  get categoriesFormGroupSelectedIds(): string[] {
    let ids: string[] = [];
    for (var key in this.categoriesFormGroup.controls) {
      if (this.categoriesFormGroup.controls[key].value) {
        ids.push(key);
      }
      else {
        ids = ids.filter(id => id !== key);
      }
    }
    return ids;
  }

하나 이상의 확인란을 선택한 사용자 지정 검증기

검증자가 X 확인란을 선택했는지 확인하도록 했습니다. 기본적으로 하나의 확인란에 대해서만 확인합니다.

export function atLeastOneCheckboxCheckedValidator(minRequired = 1): ValidatorFn {
  return function validate(formGroup: FormGroup) {
    let checked = 0;

    Object.keys(formGroup.controls).forEach(key => {
      const control = formGroup.controls[key];

      if (control.value) {
        checked++;
      }
    });

    if (checked < minRequired) {
      return {
        requireCheckboxToBeChecked: true,
      };
    }

    return null;
  };
}

JSON 형식의 확인란 값을 찾는 경우

{ "name": "", "countries": [ { "US": true }, { "Germany": true }, { "France": true } ] }

여기 전체 예가 있습니다.

질문에 있는 국가 이름 대신 국가 이름을 확인란 값으로 사용한 것에 대해 사과드립니다.추가 설명 -

양식에 대한 양식 그룹 만들기

 createForm() {

    //Form Group for a Hero Form
    this.heroForm = this.fb.group({
      name: '',
      countries: this.fb.array([])
    });

    let countries=['US','Germany','France'];

    this.setCountries(countries);}
 }

각 확인란을 확인란 값이 유일한 속성인 개체로 구성된 FormGroup으로 지정합니다.

 setCountries(countries:string[]) {

    //One Form Group for one country
    const countriesFGs = countries.map(country =>{
            let obj={};obj[country]=true;
            return this.fb.group(obj)
    });

    const countryFormArray = this.fb.array(countriesFGs);
    this.heroForm.setControl('countries', countryFormArray);
  }

확인란의 FormGroups 배열은 상위 양식의 '국가'에 대한 컨트롤을 설정하는 데 사용됩니다.

  get countries(): FormArray {
      return this.heroForm.get('countries') as FormArray;
  };

템플릿에서 파이프를 사용하여 확인란 컨트롤의 이름을 가져옵니다.

  <div formArrayName="countries" class="well well-lg">
      <div *ngFor="let country of countries.controls; let i=index" [formGroupName]="i" >
          <div *ngFor="let key of country.controls | mapToKeys" >
              <input type="checkbox" formControlName="{{key.key}}">{{key.key}}
          </div>
      </div>
  </div>

Angular 반응형(https://angular.io/guide/reactive-forms) )을 사용하려는 경우.

하나의 양식 컨트롤을 사용하여 확인란 그룹의 출력 값을 관리할 수 있습니다.

요소

import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { flow } from 'lodash';
import { flatMap, filter } from 'lodash/fp';

@Component({
  selector: 'multi-checkbox',
  templateUrl: './multi-checkbox.layout.html',
})
export class MultiChecboxComponent  {

  checklistState = [ 
      {
        label: 'Frodo Baggins',
        value: 'frodo_baggins',
        checked: false
      },
      {
        label: 'Samwise Gamgee',
        value: 'samwise_gamgee',
        checked: true,
      },
      {
        label: 'Merry Brandybuck',
        value: 'merry_brandybuck',
        checked: false
      }
    ];

  form = new FormGroup({
    checklist : new FormControl(this.flattenValues(this.checklistState)),
  });


  checklist = this.form.get('checklist');

  onChecklistChange(checked, checkbox) {
    checkbox.checked = checked;
    this.checklist.setValue(this.flattenValues(this.checklistState));
  }

  flattenValues(checkboxes) {
    const flattenedValues = flow([
      filter(checkbox => checkbox.checked),
      flatMap(checkbox => checkbox.value )
    ])(checkboxes)
    return flattenedValues.join(',');
  }
}

html

<form [formGroup]="form">
    <label *ngFor="let checkbox of checklistState" class="checkbox-control">
    <input type="checkbox" (change)="onChecklistChange($event.target.checked, checkbox)" [checked]="checkbox.checked" [value]="checkbox.value" /> {{ checkbox.label }}
  </label>
</form>

checklistState

체크리스트 입력의 모델/상태를 관리합니다.이 모델을 사용하면 현재 상태를 필요한 값 형식에 매핑할 수 있습니다.

모델:

{
   label: 'Value 1',
   value: 'value_1',
   checked: false
},
{
  label: 'Samwise Gamgee',
  value: 'samwise_gamgee',
  checked: true,
},
{
  label: 'Merry Brandybuck',
  value: 'merry_brandybuck',
  checked: false
}

checklist 컨트롤

이 컨트롤은 저장할 값을 저장합니다. 예를 들어

출력: 값출력:"value_1,value_2"

https://stackblitz.com/edit/angular-multi-checklist 에서 데모 보기

이벤트를 클릭한 다음 true 값을 수동으로 확인란이 나타내는 이름으로 변경하면 이름 또는 true가 동일하게 평가되므로 true/false 목록 대신 모든 값을 가져올 수 있습니다.예:

구성요소.구성요소

<form [formGroup]="customForm" (ngSubmit)="onSubmit()">
    <div class="form-group" *ngFor="let parameter of parameters"> <!--I iterate here to list all my checkboxes -->
        <label class="control-label" for="{{parameter.Title}}"> {{parameter.Title}} </label>
            <div class="checkbox">
              <input
                  type="checkbox"
                  id="{{parameter.Title}}"
                  formControlName="{{parameter.Title}}"
                  (change)="onCheckboxChange($event)"
                  > <!-- ^^THIS^^ is the important part -->
             </div>
      </div>
 </form>

구성 요소.ts

onCheckboxChange(event) {
    //We want to get back what the name of the checkbox represents, so I'm intercepting the event and
    //manually changing the value from true to the name of what is being checked.

    //check if the value is true first, if it is then change it to the name of the value
    //this way when it's set to false it will skip over this and make it false, thus unchecking
    //the box
    if(this.customForm.get(event.target.id).value) {
        this.customForm.patchValue({[event.target.id] : event.target.id}); //make sure to have the square brackets
    }
}

이렇게 하면 이벤트가 Angular Forms에 의해 true 또는 false로 이미 변경된 후에 이벤트가 포착됩니다. 사실이면 확인란이 나타내는 이름으로 이름을 변경합니다. 필요한 경우 확인란이 true/false로 검사되는 경우에도 true로 평가됩니다.

분명히, 이것은 매우 흔한 문제이고 아무도 "완벽한" 해결책을 가지고 있지 않습니다.FormGroup의 기능을 확장하기 위해 객체 지향을 사용하여 상당히 우아한 솔루션을 개발할 수 있었다고 생각합니다.

원하는 API

단일 개체에서 다음을 수행할 수 있습니다.

  • 각 확인란에 대한 양식 제어
  • 각 확인란의 레이블 및 값
  • 선택한 모든 확인란의 값

따라서 HTML 구조는 다음과 같이 단순할 수 있습니다.

<div *ngFor="let item of checkboxGroup.items">
   <input type="checkbox" [id]="item.value" [formControl]="item.control">
   <label [for]="item.value">{{ item.label }}</label>
 </div>

타이프스크립트 부분은 다음과 같이 단순할 수 있습니다.

checkboxGroup.value; // return the list of selected item values
checkboxGroup.control.valid; // return if there's at least one checked value

해결책

에서 볼 수 HTML은checkboxGroup속성이 세 개 이상인 클래스여야 합니다.

  • 항목(각 항목은 값, 레이블 및 FormControl이 있는 확인란)
  • value(선택한 모든 항목을 가져옵니다)
  • control(FormArray 컨트롤을 가져옵니다)

수업 내용은 다음과 같습니다.

// # This represents a single checkbox item
class CheckboxItemControl {
  label: string; // value to be shown in the UI
  value: string; // value to be saved in backend

  control: FormControl;

  constructor({ label, value, defaultValue = false }: { label: string; value: string; defaultValue?: boolean }) {
    this.label = label;
    this.value = value;

    this.control = new FormControl(defaultValue || false);
  }

  get selected(): boolean {
    return Boolean(this.control.value);
  }
}

// # This represents a checkbox group, with several items
class CheckboxGroupControl {
  name?: string; // name of the checkbox group

  items: CheckboxItemControl[];
  control: FormArray;

  constructor(name: string, items: CheckboxItemControl[]) {
    this.name = name;
    this.items = items;

    this.control = new FormArray(this.getAllItemsControls(), CheckboxGroupControl.emptyArrayFormValidator);
  }

  get value(): string[] {
    return this.selectedItems.map(item => item.value);
  }

  private get selectedItems(): CheckboxItemControl[] {
    return this.items.filter(item => item.selected);
  }

  private getAllItemsControls(): FormControl[] {
    return this.items.map(item => item.control);
  }

  private static emptyArrayFormValidator(control: FormControl) {
    const valid = (control.value as boolean[]).some(Boolean);

    // @todo improve error message
    return valid ? null : {
      error: 'empty'
    };
  }
}

각 를 노출하는지 할 수 .object.value그리고.object.control를을 쉽게 얻을 수 있습니다.를 사용하면 필요한 모든 것을 쉽게 얻을 수 있습니다.

사용.

이제 실제로 어떻게 작동하는지 살펴보겠습니다.

HTML

<div *ngFor="let item of checkboxGroup.items">
   <input type="checkbox" [id]="item.value" [formControl]="item.control">
   <label [for]="item.value">{{ item.label }}</label>
 </div>

활자 원고

checkboxGroup;

ngOnInit() {
  this.createFormInputs();
}

private createFormInputs() {
  const checkboxItems = [
    new CheckboxItemControl({ value: 'checkbox-1', label: 'Checkbox 1' }),
    new CheckboxItemControl({ value: 'checkbox-2', label: 'Checkbox 2' }),
    new CheckboxItemControl({ value: 'checkbox-3', label: 'Checkbox 3', defaultValue: true })
  ];

  this.checkboxGroup = new CheckboxGroupControl('name_of_group', checkboxItems);

  this.form = new FormGroup({
    checkbox: this.checkboxGroup.control
  });

  // this.checkboxGroup.value returns ['checkbox-1', ...] for the selected checkboxes
  // this.checkboxGroup.valid returns if there's any checkbox selected
  // this.form.valid returns if the whole form is valid. Which is useful if you include others checkbox groups
}

기타 자원

  • 기사는 제가 이 해결책을 생각해 낼 수 있게 해줍니다.

- 5 Material 했습니다. - Angular 5에 대해 해결했습니다.
은 연은다통이집니다루어해음결을 통해 .

formArrayName="알림"

(변경)="updateChkbxArray(n.id , $event.checked, '알림')"

이렇게 하면 하나의 양식에서 여러 개의 확인란 배열에 대해 작동할 수 있습니다.매번 연결할 컨트롤 배열의 이름을 설정하기만 하면 됩니다.

constructor(
  private fb: FormBuilder,
  private http: Http,
  private codeTableService: CodeTablesService) {

  this.codeTableService.getnotifications().subscribe(response => {
      this.notifications = response;
    })
    ...
}


createForm() {
  this.form = this.fb.group({
    notification: this.fb.array([])...
  });
}

ngOnInit() {
  this.createForm();
}

updateChkbxArray(id, isChecked, key) {
  const chkArray = < FormArray > this.form.get(key);
  if (isChecked) {
    chkArray.push(new FormControl(id));
  } else {
    let idx = chkArray.controls.findIndex(x => x.value == id);
    chkArray.removeAt(idx);
  }
}
<div class="col-md-12">
  <section class="checkbox-section text-center" *ngIf="notifications  && notifications.length > 0">
    <label class="example-margin">Notifications to send:</label>
    <p *ngFor="let n of notifications; let i = index" formArrayName="notification">
      <mat-checkbox class="checkbox-margin" (change)="updateChkbxArray(n.id, $event.checked, 'notification')" value="n.id">{{n.description}}</mat-checkbox>
    </p>
  </section>
</div>

마지막으로 저장/업데이트할 원본 레코드 ID 배열과 함께 양식을 저장합니다.UI 보기

양식의 json에 관련된 부분.

개선을 위한 어떤 발언도 기꺼이 할 것입니다.

구성 요소:

formGroup: FormGroup;

games = [
  { keyword: 'hots', score: 9 },
  { keyword: 'xcom', score: 9 },
  { keyword: 'fallout', score: 8 }
];

constructor(private fb: FormBuilder) {}

ngOnInit() {
  this.formGroup = this.fb.group(
    this.games.reduce((obj, game) => {
      obj[game.keyword] = [false];
      return obj;
    }, {})
  );

  const enabledGames$ = this.formGroup.valueChanges.pipe(
    map(value =>
      Object.entries(value)
        .filter(([key, enabled]) => enabled)
        .map(([key]) => 
          this.games.find(({ keyword }) => keyword === key)
        )
    )
  );
}

템플릿:

<form [formGroup]="formGroup">
  <div *ngFor="let control of formGroup.controls | keyvalue">
    <input
      type="checkbox"
      [formControlName]="control.key">
    <label>
      {{ control.key }}
    </label>
  </div>
</form>

FormGroups의 FormArray를 사용하여 이 작업을 수행할 수 있었습니다.양식 그룹은 두 개의 컨트롤로 구성됩니다.하나는 데이터용이고 하나는 선택된 부울을 저장하는 것입니다.

TS

options: options[] = [{id: 1, text: option1}, {id: 2, text: option2}];

this.fb.group({
  options: this.fb.array([])
})    

populateFormArray() {    
  this.options.forEach(option => {                       
    let checked = ***is checked logic here***;            
    this.checkboxGroup.get('options').push(this.createOptionGroup(option, checked))
  });       
}  

createOptionGroup(option: Option, checked: boolean) {
  return this.fb.group({      
    option: this.fb.control(option),
    checked: this.fb.control(checked)
  });
}

HTML

이렇게 하면 옵션을 반복하여 선택한 컨트롤에 바인딩할 수 있습니다.

<form [formGroup]="checkboxGroup">
  <div formArrayName="options" *ngFor="let option of options; index as i">   
    <div [formGroupName]="i">
      <input type="checkbox" formControlName="checked" />
      {{ option.text }}
    </div>
  </div>       
</form>

산출량

양식이 양식의 데이터를 반환합니다.{option: Option, checked: boolean}[].

아래 코드를 사용하여 선택한 옵션 목록을 얻을 수 있습니다.

 this.checkboxGroup.get('options').value.filter(el => el.checked).map(el => el.option);

양방향 바인딩 포함

my.component.component.cisco

<form [formGroup]="formGroup" (ngSubmit)="onSubmit()">

  <div formGroupName="options">
    <mat-checkbox formControlName="myVal1">My Value 1</mat-checkbox>
    <mat-checkbox formControlName="myVal2">My Value 2</mat-checkbox>
  </div>


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

</form>

my.component.ts

export class ClientStatementReportComponent implements OnInit {

  formGroup: FormGroup;

  ngOnInit(): void {

    this.formGroup = new FormGroup({
      options: new FormGroup({
        myVal1: new FormControl(false),
        myVal2: new FormControl(false)
      }),
    });
  }

  onSubmit() {
    const options = this.formGroup.value.options;
    const result = Object.keys(options).filter(key => options[key])
    // is array of checked elements e.g. ["myVal1"]
  }
}

(상태를 형성하기 위해) 단방향 바인딩 사용

my.component.component.cisco

<form [formGroup]="formGroup">

  <mat-checkbox value="val-1" (change)="selectOption($event)">Value 1</mat-checkbox>
  <mat-checkbox value="val-2" (change)="selectOption($event)">Value 2</mat-checkbox>
 
</form>

my.component.ts

export class MyComponent implements OnInit {

  formGroup: FormGroup;

  ngOnInit(): void {
    this.formGroup = new FormGroup({
      options: new FormControl([]),
    });
  }

  selectOption($event: MatCheckboxChange) {
    const value = $event.source.value;
    const optionControl = this.formGroup.controls['options']
    const options = optionControl.value as [];

    if(checked){
      optionControl.setValue([...options, value])
    } else {
      optionControl.setValue(options.filter(option => option !== value))
    }
  }   
}

다음은 표준 FormGroup에 불과하고 템플릿에 미치는 영향을 최소화하면서 쉽게 이를 달성할 수 있는 일련의 지침입니다.

StackBliz 데모 여기서

구성요소 내에서 FormGroup을 정의합니다.

formGroup = new FormGroup({
  resultArray: new FormControl([])
})

에 템릿내다설다니합정음을에를 합니다.formControlName모든 체크박스를 새로운 것으로 포장하는 디브에서.checkboxArray지시도 마찬가지입니다.

에서 각 확 란 에 설 정을 합니다.checkboxArrayKey 으로 " " " 를 선택합니다.

<form [formGroup]="formGroup">
  <!-- ... -->
  <div checkboxArray formControlName="resultArray">
    <div *ngFor="let option of checkboxOptions">
      <input type="checkbox" [checkboxArrayKey]="option.value">
      <label>{{option.label}}</label>
    </div>
  </div>
  <!-- ... -->
</form>

이제 양식 컨트롤에 선택된 확인란만 반영하는 값이 표시됩니다.

지침 자체가 약간 거칠고 정리가 필요할 수 있습니다.

import { AfterContentInit, ContentChildren, Directive, ElementRef, forwardRef, Input, OnDestroy, Output, QueryList, Renderer2 } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { merge, of, Subject, takeUntil } from "rxjs";

@Directive({
    selector: 'input[type=checkbox][checkboxArrayKey]',
    host: {
        '(change)': 'onChange($event.target.checked)', 
        '(blur)': 'onTouched()'
    }
})
export class CheckboxArrayKey {
    @Input("checkboxArrayKey") key: any;
    parent?: CheckboxArrayValueAccessor;
    state: boolean = false;

    constructor(private renderer: Renderer2, private element: ElementRef) {
    }

    writeValue(value: boolean) {
        this.state = value;
        this.renderer.setProperty(this.element.nativeElement, "checked", value);
    }

    onChange(value: boolean) {
        this.state = value;
        this.parent?.onChange();
    }

    onTouched() {
        this.parent?.onTouched();
    }
    
    setDisabledState(isDisabled: boolean) {
        this.renderer.setProperty(this.element.nativeElement, "disabled", isDisabled)
    }
}


export const CHECKBOX_ARRAY_VALUE_ACCESSOR: any = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CheckboxArrayValueAccessor),
    multi: true
}


@Directive({
    selector: '[checkboxArray][formControlName], [checkboxArray][formControl], [checkboxArray][ngModel]',
    providers: [CHECKBOX_ARRAY_VALUE_ACCESSOR]
})
export class CheckboxArrayValueAccessor implements ControlValueAccessor, AfterContentInit, OnDestroy {
    @ContentChildren(CheckboxArrayKey, {descendants: true}) checkboxes?: QueryList<CheckboxArrayKey>;

    private state: any[] = [];
    private destroy = new Subject<void>();
    private onWriteValue = new Subject<void>();
    private _onChange = (_: any) => {};
    private _onTouched = () => {};

    ngAfterContentInit() {
        // Checkboxes will be defined by now - the if is a hack to resolve the potential undefined state
        if (this.checkboxes) {
            merge(of(0), this.checkboxes.changes, this.onWriteValue).pipe(
                takeUntil(this.destroy),
            ).subscribe({ next: () => {
                this.linkChildren();
            }});
        }
    }

    private linkChildren() {
        var me = this;
        var lastState = this.state;

        this.checkboxes?.forEach(chk => { 
            chk.writeValue(lastState.indexOf(chk.key) > -1); 
            chk.parent = me;
        });

        //Hack to avoid changes after a change detection cycle
        Promise.resolve(null).then(() => this.onChange());
    }

    writeValue(obj: any): void {
        if (Array.isArray(obj)) {
            this.state = obj;
            this.onWriteValue.next();
        }
    }

    registerOnChange(fn: (_: any) => void): void {
        this._onChange = fn;
    }

    registerOnTouched(fn: () => void): void {
        this._onTouched = fn;
    }

    setDisabledState(isDisabled: boolean): void {
        this.checkboxes?.forEach(chk => chk.setDisabledState(isDisabled));
    }

    onChange() {
        this._onChange(this.checkboxes?.filter(chk => chk.state).map(chk => chk.key) || []);
    }

    onTouched() {
        this._onTouched();
    }

    ngOnDestroy(): void {
        this.destroy.next();
        this.destroy.complete();
        this.onWriteValue.complete();
    }
}

그러나 매우 다양하고 방해가 되지 않는 구현이 가능합니다.

템플릿 부품:-

    <div class="form-group">
         <label for="options">Options:</label>
         <div *ngFor="let option of options">
            <label>
                <input type="checkbox"
                   name="options"
                   value="{{option.value}}"
                   [(ngModel)]="option.checked"
                                />
                  {{option.name}}
                  </label>
              </div>
              <br/>
         <button (click)="getselectedOptions()"  >Get Selected Items</button>
     </div>

컨트롤러 부품:-

        export class Angular2NgFor {

          constructor() {
             this.options = [
              {name:'OptionA', value:'first_opt', checked:true},
              {name:'OptionB', value:'second_opt', checked:false},
              {name:'OptionC', value:'third_opt', checked:true}
             ];


             this.getselectedOptions = function() {
               alert(this.options
                  .filter(opt => opt.checked)
                  .map(opt => opt.value));
                }
             }

        }

5센트 추가) 내 질문 모델

{
   name: "what_is_it",
   options:[
     {
      label: 'Option name',
      value: '1'
     },
     {
      label: 'Option name 2',
      value: '2'
     }
   ]
}

template.vmdk

<div class="question"  formGroupName="{{ question.name }}">
<div *ngFor="let opt of question.options; index as i" class="question__answer" >
  <input 
    type="checkbox" id="{{question.name}}_{{i}}"
    [name]="question.name" class="hidden question__input" 
    [value]="opt.value" 
    [formControlName]="opt.label"
   >
  <label for="{{question.name}}_{{i}}" class="question__label question__label_checkbox">
      {{opt.label}}
  </label>
</div>

구성 요소.ts

 onSubmit() {
    let formModel = {};
    for (let key in this.form.value) {
      if (typeof this.form.value[key] !== 'object') { 
        formModel[key] = this.form.value[key]
      } else { //if formgroup item
        formModel[key] = '';
        for (let k in this.form.value[key]) {
          if (this.form.value[key][k])
            formModel[key] = formModel[key] + k + ';'; //create string with ';' separators like 'a;b;c'
        }
      }
    }
     console.log(formModel)
   }

템플릿

 <div>
    <input name="fruits" type="checkbox" value="orange" (change)="change($event)">
    <input name="fruits" type="checkbox" value="apple" (change)="change($event)">
    <input name="fruits" type="checkbox" value="banana" (change)="change($event)">
</div>

요소


formGroup = 이것입니다.formBuilder.group({과일: [] //["오렌지", "바나나", ...]})
변경(이벤트:이벤트) {let target = (event.target을 HTMLInputElement로 지정);
let array = (this.formGroup.get(target.name )?어레이로 값 지정);
    
if (목표)&&!array.find를 선택했습니다(예: => {return (변수 === target.value);
})) {array.value(target.value)// 요소가 없습니다. push(확인)}그렇지 않으면 {array.splice(array.findIndex(요소 => {)return(수정 === target.value);//요소 삭제(수정)}), 1)}}

저는 항상 Angular Material List를 사용하지만 이렇게 할 것입니다.

https://material.angular.io/components/list/overview

이러한 작업을 위해 모든 것이 공장에서 제공됩니다.

언급URL : https://stackoverflow.com/questions/40927167/angular-reactiveforms-producing-an-array-of-checkbox-values