Angular ReactiveForms: 生成一个复选框值数组?

给定一个绑定到相同 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', ...]
283555 次浏览

模板部分:-

    <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));
}
}


}

这是一个使用 FormArray https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html的好地方

首先,我们将使用 FormBuilder或新建一个 FormArray来构建我们的控件数组

造型师

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

新的 FormArray

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


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

这很容易做到,但是接下来我们要修改我们的模板,让模板引擎处理我们如何绑定到我们的控件:

翻译: 奇芳

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

在这里,我们在 myValues FormArray中迭代我们的 FormControls集合,对于每个控件,我们将 [formControl]绑定到该控件,而不是 FormArray控件,<div>\{\{checkboxGroup.controls['myValues'].value}}</div>生成 true,false,true,同时也使您的模板语法少一点手动。

您可以使用以下示例: http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview进行查找

在 silentsod 答案的帮助下,我在 formBuilder 中编写了一个获取值而不是状态的解决方案。

我使用一个方法来添加或删除 formArray 中的值。这可能是个糟糕的方法,但是很有效!

组件.html

<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>

组件

// 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 的函数。

单击时创建一个事件,然后手动将 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>

组件

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,我会将名称更改为复选框所代表的名称,如果需要的话,如果它也被选中为 true/false,那么它也会被计算为 true。

如果您正在寻找 JSON 格式的复选框值

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

完整的例子在这里

我为使用国家名称作为复选框值而不是问题中的值而道歉

为表单创建一个 FormGroup

 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);
}

复选框的 FormGroup 数组用于设置父 Form 中“国家”的控件。

  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>

加上我的5美分) 我的问题模型

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

翻译: 奇芳

<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>

组件

 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)
}

我的解决方案-解决它的角度5与材料视图
连接是通过

FormArrayName = “通知”

(change) = “ updateChkbxArray (n.id,$event.check,‘ tification’)”

通过这种方式,它可以在一个表单中处理多个复选框数组。 只需设置每次连接的控件数组的名称。

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 的数组来保存/更新表单。 The UI View

The relevat part of the json of the form

将乐意提出任何改进意见。

与以前的版本相比,在 Angular 6中做到这一点要容易得多,即使复选框信息是从 API 异步填充的。

首先要意识到的是,由于角6的 keyvalue管道,我们不需要再使用 FormArray,而是可以嵌套一个 FormGroup

首先,将 FormBuilder 传递到构造函数中

constructor(
private _formBuilder: FormBuilder,
) { }

然后初始化我们的形式。

ngOnInit() {


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


}

当我们的复选框选项数据可用时,迭代它,我们可以将它作为命名的 FormControl直接推送到嵌套的 FormGroup中,而不必依赖于编号索引的查找数组。

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>

如果你想使用角度反应形式(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
}

表格管制

此控件将要保存的值存储为

输出值: "value_1,value_2"

请看 https://stackblitz.com/edit/angular-multi-checklist的演示

DR

  1. 我更喜欢使用 FormGroup 来填充复选框列表
  2. 编写一个自定义验证器来选中至少一个复选框
  3. 工作示例 https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

这有时也让我感到震惊,所以我尝试了 FormArray 和 FormGroup 两种方法。

大多数时候,复选框列表是在服务器上填充的,我通过 API 接收它。但是有时候您会有一组带有预定义值的静态复选框。对于每个用例,都将使用相应的 FormArray 或 FormGroup。

基本上 FormArrayFormGroup的变体。关键区别在于它的数据被序列化为数组(而不是在 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));
})

建立类别列表有两种方法。

1. 表格数组

  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>

这个 buildCategoryFormGroup将返回一个 FormArray。它还接受一个选定值的列表作为参数,因此如果您想重用表单来编辑数据,它可能会很有帮助。为了创建一个新的产品表单,它还不适用。

注意,当您尝试访问 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来解决这个问题

2. 表格组

formGroup将表单数据存储为对象,这需要一个到表单控件的键映射。因此,将密钥设置为 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;
}

3. 选中了至少一个复选框的自定义验证程序

我让验证程序选中了至少 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;
};
}

我没有看到一个解决方案,完全回答了这个问题,使用反应形式的最大限度,所以这里是我的解决方案相同。


摘要

下面是详细解释的精髓以及 StackBlitz 示例。

  1. 对复选框使用 FormArray并初始化表单。
  2. 当您希望表单显示某些内容但是在组件中存储其他内容时,valueChanges可观察内容非常适合。将 true/false值映射到这里所需的值。
  3. 在提交时过滤掉 false值。
  4. valueChanges退订可观察到。

StackBlitz 的例子


详细解释

使用 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

接下来,我们需要在模板中注册这些表单变量,并迭代 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>

充分利用 valueChanges 可观察到的变化

这里有一部分我没有看到任何答案提到这里。在这种情况下,我们希望显示所说的数据,但存储它作为其他东西,valueChanges观察是非常有帮助的。使用 valueChanges,我们可以观察 checkboxesmap的变化,从 FormArray接收到的 true/false值变成所需的数据。注意,这不会改变复选框的选择,因为传递给复选框的任何 真心话值都会将其标记为选中,反之亦然。

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数组,并在复选框被标记为 true的情况下返回 value,否则返回 falseemitEvent: false在这里很重要,因为如果没有设置 FormArray值,就会导致 valueChanges发出一个事件,从而产生一个无穷无尽的循环。通过将 emitEvent设置为 false,我们可以确保当我们在这里设置值时,valueChanges可观察到的不会发射。

过滤掉虚假值

我们不能直接过滤 FormArray中的 false值,因为这样做会搞乱模板,因为它们被绑定到复选框。因此,最好的解决方案是在提交过程中过滤掉 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();
}

注意: 有一种特殊情况,在 valueChanges中不能将值设置为 FormArray,即如果复选框的值设置为数字 0。这将使复选框看起来不能被选中,因为选中该复选框将把 FormControl设置为数字 0(一个虚假的值) ,因此保持它不被选中。最好不要使用数字 0作为值,但是如果需要的话,你必须有条件地将 0设置为某个真值,比如字符串 '0'或者仅仅是简单的 true,然后在提交时,将它转换回数字 0

StackBlitz 的例子

StackBlitz 还提供了代码,用于在需要将默认值传递给复选框时将其标记为已在 UI 中选中。

我能够使用 FormArray 的 FormGroup 来实现这一点。FormGroup 由两个控件组成。一个用于数据,一个用于存储检查的布尔值。

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)
});
}

超文本标示语言

这允许您循环访问这些选项并绑定到相应的选中控件。

<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);

组成部分:

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>

显然,这是一个非常普遍的问题,没有人有一个“完美”的解决方案。我相信我能够提供一个非常优雅的解决方案,使用面向对象来扩展 FormGroup 的功能。

理想的空气污染指数

在一个单一的对象,我希望能够有:

  • 每个复选框的表单控件
  • 每个复选框的标签和值
  • 所有选中复选框的值

因此 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 的复选框)
  • 值(获取所有选定的项)
  • 控件(获取 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'
};
}
}

您可以看到每个类如何公开一个简单的 API (object.valueobject.control) ,它允许您轻松获得所需的所有内容。

用法

那么让我们来看看它是如何工作的:

超文本标示语言

<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
}

其他资源

模板

 <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 = this.formBuilder.group(
{
fruits: [[]]  //["Orange","Banana",...]
})


change(event: Event) {
let target = (event.target as HTMLInputElement);
let array = (this.formGroup.get(target.name)?.value as Array);
    

if (target.checked && !array.find(element => {
return (element === target.value);
})) {
array.push(target.value)// element not exists, push (check)
}
else {
array.splice(array.findIndex(element => {
return (element === target.value);//delete element (uncheck)
}), 1)
}
}


这是我将如何做到这一点,虽然我总是使用角材料列表

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

这些任务的一切都来自工厂

双向绑定

My.Component. html

<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>

我的组件

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. html

<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>

我的组件

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))
}
}
}