ng实现RadioGroup/CheckboxGroup组件

本文大纲
  1. 1. 父组件:
    1. 1.1. 模板:parent.component.html
    2. 1.2. TS:parent.component.ts
  2. 2. checkbox-group组件:
    1. 2.1. 模板:checkbox-group.component.html
    2. 2.2. TS:checkbox-group.component.ts
  3. 3. radiobtn-group组件:
    1. 3.1. 模板:radiobtn-group.component.html
    2. 3.2. Ts:radiobtn-group.component.ts

angular实战项目已完成,在此记录一个简单的RadioGroup和CheckboxGroup组件实现。完了下一步就该进入vue的学习和实战了。

父组件:

模板:parent.component.html

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<form [formGroup]="try" style="border:1px solid #333;margin:0 50px;">
<h2>响应式</h2>
<checkbox-group
[options]="cksDatas"
[disableds]="ckbDisableds"
formControlName="cks"
(outChange)="onCksChange($event)"
></checkbox-group>&nbsp;&nbsp;&nbsp;&nbsp;
<button type="button" (click)="gouXuanCkb()" style="padding:unset">只勾选音乐</button>&nbsp;
<button type="button" (click)="jinYongCkb()" style="padding:unset">只禁用电影和音乐</button>&nbsp;--&gt;&nbsp;
ctrValue: {{try.get('cks').value | json}}
<div style="border-bottom:1px dashed #ccc;margin-bottom:10px;"></div>

<radiobtn-group
[options]="rdoDatas"
[disableds]="rdoDisableds"
formControlName="rdos"
(outChange)="onRdoChange($event)"
></radiobtn-group>&nbsp;&nbsp;&nbsp;&nbsp;
<button type="button" (click)="gouXuanRdo()" style="padding:unset">勾选音乐</button>&nbsp;
<button type="button" (click)="jinYongRdo()" style="padding:unset">只禁用电影和音乐</button>&nbsp;--&gt;&nbsp;
ctrValue: {{try.get('rdos').value | json}}
<div style="border-bottom:1px dashed #ccc;margin-bottom:10px;"></div>

<radiobtn-group
[options]="rdoDatas2"
formControlName="rdos2"
(outChange)="onRdoChange2($event)"
></radiobtn-group>&nbsp;--&gt;&nbsp;
ctrValue: {{try.get('rdos2').value}}
<div style="border-top:1px dashed #ccc;margin-top:10px;">
formValue ==> {{try.value | json}}
</div>
</form>

<form #temForm="ngForm" style="border:1px solid #333;margin:20px 50px 0;">
<h2>模板驱动式</h2>
<radiobtn-group
[options]="rdoDatas2"
name="rdo1"
[(ngModel)]="rdosBBB"
(outChange)="onRdoChange2($event)"
#rdoGrp="ngModel"
></radiobtn-group>&nbsp;&nbsp;&nbsp;--&gt;&nbsp;&nbsp;
ctrValue: {{rdoGrp.value}}
<div style="border-bottom:1px dashed #ccc;margin-bottom:10px;"></div>
<checkbox-group
[options]="cksDatas2"
name="cks1"
[(ngModel)]="cksBBB"
#ckbGrp="ngModel"
(outChange)="onCksChange2($event)"
></checkbox-group>&nbsp;&nbsp;&nbsp;--&gt;&nbsp;&nbsp;
ctrValue: {{ckbGrp.value | json}}
<div style="border-top:1px dashed #ccc;margin-top:10px;">
formValue ==> {{temForm.value | json}}
</div>
</form>

TS:parent.component.ts

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';

@Component({
selector: 'parent-ctr-group',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class TryCtrGroupComponent implements OnInit {

try = new FormGroup({
// cks: new FormControl(),
cks: new FormControl(['song']),
rdos: new FormControl('song'),
rdos2: new FormControl()
});

cksDatas = [
{ name: '电影', value: 'movie' }, { name: '音乐', value: 'song' }, { name: '阅读', value: 'read' },
{ name: '登山', value: 'mountain' }, { name: '游泳', value: 'swim' }
];
rdoDatas = [
{ name: '电影', value: 'movie' }, { name: '音乐', value: 'song' }, { name: '阅读', value: 'read' },
{ name: '登山', value: 'mountain' }, { name: '游泳', value: 'swim' }
];
rdoDatas2 = [
{ name: 'a', value: 1 }, { name: 'b', value: 2 }, { name: 'cc', value: 3 },
{ name: 'd', value: 4 }, { name: 'e', value: 5 }
];
cksDatas2 = [
{ name: 'a', value: 1 }, { name: 'b', value: 2 }, { name: 'cc', value: 3 },
{ name: 'd', value: 4 }, { name: 'e', value: 5 }
];
ckbDisableds = ['swim'];
rdoDisableds = ['swim'];

rdosBBB = '';
cksBBB = [];

constructor() { }

ngOnInit() {
// this.try.patchValue({cks: ['mountain', 'swim']});
}
gouXuanCkb() { this.try.patchValue({cks: ['song']}); }
gouXuanRdo() { this.try.patchValue({rdos: 'song'}); }
jinYongCkb() { this.ckbDisableds = ['movie', 'song']; }
jinYongRdo() { this.rdoDisableds = ['movie', 'song']; }
onCksChange(obj: any) { console.log(obj); }
onRdoChange(obj: any) { console.log(obj); }
onRdoChange2(obj: any) { console.log(obj); }
onCksChange2(obj: any) { console.log(obj); }

}

checkbox-group组件:

模板:checkbox-group.component.html

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
<label *ngFor="let e of options">
<input
type="checkbox"
[disabled]="ifDisabledMe(e)"
[checked]="this.model.length && this.model.indexOf(e.value) > -1"
[value]="e.value"
(change)="myChange(e)">
{{ e.name }}
</label>

TS:checkbox-group.component.ts

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { Component, OnInit, Input, Output, forwardRef, EventEmitter } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

@Component({
// tslint:disable-next-line:component-selector
selector: 'checkbox-group',
templateUrl: './checkbox-group.component.html',
styleUrls: ['./checkbox-group.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxGroupComponent),
multi: true
}]
})
export class CheckboxGroupComponent implements OnInit, ControlValueAccessor {

@Input() options: any = [];
@Input() disableds: any = []; // 可以在父组件动态更改
@Output() outChange: EventEmitter<any> = new EventEmitter();
model: any = [];
onChange = (_: any) => { };
constructor() { }
ngOnInit() {}
ifDisabledMe(obj: any) {
return this.disableds.some((v: any) => v === obj.value );
}
myChange(obj: any) {
const { value } = obj;
const index = this.model.indexOf(value);
let dos: boolean;
if (index > -1) {
this.model.splice(index, 1);
this.onChange(this.model);
dos = false;
} else {
this.model.push(value);
this.onChange(this.model);
dos = true;
}
// for user event
this.outChange.emit({
active: {...obj, ifCheck: dos},
checks: this.model
});
}
writeValue(value: any) {
if (value) {
if (this.model.sort().toString() !== value.sort().toString()) { // 此判断是:如果js动态选中和已有选中不同,才触发
// for js
this.outChange.emit({ checks: value });
}
if (value.length >= 1) {
this.model = value;
} else {
this.model = [];
}
} else {
this.model = [];
}
}
registerOnChange(fn: any) { this.onChange = fn; }
registerOnTouched(fn: any): void {}
}

radiobtn-group组件:

模板:radiobtn-group.component.html

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
<label *ngFor="let e of options">
<input
type="radio"
[disabled]="ifDisabledMe(e)"
[checked]="this.model==e.value"
[value]="e.value"
(change)="myChange(e)"
[attr.name]="privateName"
>
{{ e.name }}
</label>

Ts:radiobtn-group.component.ts

代码折叠 代码展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import { Component, OnInit, Input, Output, forwardRef, EventEmitter } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

@Component({
// tslint:disable-next-line:component-selector
selector: 'radiobtn-group',
templateUrl: './radiobtn-group.component.html',
styleUrls: ['./radiobtn-group.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RadiobtnGroupComponent),
multi: true
}]
})
export class RadiobtnGroupComponent implements OnInit, ControlValueAccessor {

@Input() options: any = [];
@Input() disableds: any = []; // 可以在父组件动态更改
@Output() outChange: EventEmitter<any> = new EventEmitter();
privateName: string;
model: any = '';
onChange = (_: any) => { };
constructor() {
const rdm = Math.random().toString().replace(/^\d\./, '');
this.privateName = `radio-${rdm}}`;
}
ngOnInit() { }
ifDisabledMe(obj: any) {
return this.disableds.some((v: any) => v === obj.value );
}
myChange(obj: any) {
const { value } = obj;
this.model = value;
this.onChange(value);
this.outChange.emit(obj);
}
writeValue(value: any) {
if (value) {
if (this.model !== value) { this.outChange.emit(value); }
this.model = value;
} else {
this.model = '';
}
}
registerOnChange(fn: any) { this.onChange = fn; }
registerOnTouched(fn: any): void {}

}