Angular库我试图为自定义单选按钮创建一个库,它的作用是警告(黄色点)错误(红色点)信息(蓝色点)和成功(绿色点),没有Angular库就能正常工作,之后我把我的css和模板移到库里,但现在它不能正常工作了。
我有提供价值从反应从,但它不检查作为预期,我也添加了截图,在最后我期待什么,我得到什么,目前
radio-button.html
<label class="container" >
<input type="radio" #radioButton [name]="lbName" (click)="onClick($event)" [value]="lbValue"
[disabled]="lbDisabled" />
<span [class]="className"></span>
<span>
<ng-content></ng-content>
</span>
</label>
radio-button.scss
/* The container */
.container {
display: block;
position: relative;
padding-left: 35px;
margin-bottom: 12px;
cursor: pointer;
font-size: 14px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* Hide the browser's default radio button */
.container input {
position: absolute;
opacity: 0;
cursor: pointer;
}
/* Create a custom radio button */
.lb-radio {
position: absolute;
top: 0;
left: 0;
height: 20px;
width: 20px;
background-color: #eee;
border-radius: 50%;
}
.container input ~ .lb-radio--warning {
border: 1px solid darkorange;
}
.container input ~ .lb-radio--success {
border: 1px solid green;
}
.container input ~ .lb-radio--error {
border: 1px solid red;
}
.container input ~ .lb-radio--info {
border: 1px solid blue;
}
/* When the radio button is checked, add a blue background */
.container input[type='radio']:checked ~ .lb-radio--warning {
background-color: darkorange;
}
.container input[type='radio']:checked ~ .lb-radio--success {
background-color: green;
}
.container input[type='radio']:checked ~ .lb-radio--error {
background-color: red;
}
.container input[type='radio']:checked ~ .lb-radio--info {
background-color: blue;
}
/* Create the indicator (the dot/circle - hidden when not checked) */
.lb-radio::after {
content: '';
position: absolute;
display: none;
}
/* Style the indicator (dot/circle) */
.container .lb-radio::after {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 5px;
height: 5px;
border-radius: 50%;
background: white;
}
/* Show the indicator (dot/circle) when checked */
.container input[type='radio']:checked ~ .lb-radio::after {
display: block;
}
.container input[type='radio']:disabled + span {
border: 1px solid grey;
}
.container input[type='radio']:disabled ~ span {
background-image: none;
background-color: none;
color: grey;
cursor: not-allowed;
}
.container input[type='radio']:checked:disabled + span {
border: 1px solid grey;
background-color: grey;
}
.container input[type='radio']:checked:disabled ~ span {
background-image: none;
color: grey;
cursor: not-allowed;
}
radio-button.ts
import { Component, OnInit, Output, Input, EventEmitter, forwardRef} from '@angular/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
@Component({
selector: 'lb-radio-button, [lb-radio-button]',
templateUrl: './radio-button.component.html',
styleUrls: ['./radio-button.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RadioButtonComponent),
multi: true
}
]
})
export class RadioButtonComponent implements OnInit, ControlValueAccessor {
@ViewChild('radioButton') radioButton: ElementRef;
className = 'lb-radio';
value = '';
isDisabled: boolean;
@Output() checkBoxClick: EventEmitter<boolean> = new EventEmitter<boolean>();
@Input() lbRole = 'info';
@Input() lbName = 'radioButton';
@Input()
set lbDisabled(value: boolean) {
this.isDisabled = coerceBooleanProperty(value);
}
get lbDisabled() {
return this.isDisabled;
}
@Input()
set lbValue(value: string) {
this.writeValue(value);
this.onChange(value);
this.onTouched();
}
get lbValue(): string {
return this.value;
}
onChange: any = () => {};
onTouched: any = () => {};
ngOnInit() {
this.className += ` lb-radio--${this.lbRole}`;
}
onClick($event): boolean {
if (this.lbDisabled) {
return false;
}
this.writeValue($event.target.value);
this.checkBoxClick.emit($event.target.value);
}
registerOnChange(fn) {
this.onChange = fn;
}
writeValue(value) {
if (value)
this.value = value;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
}
并使用了库,但雄性单选按钮没有像预期的那样被选中。
**implementation.html**
<form [formGroup]="radioButtonForm">
<p lb-radio-button [lbValue]="'Male'" [formControlName]="nameKey.gender" [lbRole]="'success'" [lbName]="'gender'">
Male success radio button
</p>
<p lb-radio-button [lbValue]="'Female'" [formControlName]="nameKey.gender" [lbRole]="'info'" [lbName]="'gender'">
Female info radio button
</p>
<div lb-button (buttonClick)="onSubmit()" type="submit" lbType="primary">Submit Form</div>
</form>
**implementation.ts**
export class RadioButtonComponent implements OnInit {
radioButtonForm: FormGroup;
nameKey = {
gender: 'gender',
};
ngOnInit() {
this.radioButtonForm = this.formBuilder.group({
gender: ['Male', Validators.required],
});
}
onSubmit() {
alert(JSON.stringify(this.radioButtonForm.value))
}
}
预期的
目前我得到的是
Stackblitz演示 演示包含的信息比下面建议中描述的基础知识更多一些)。
使用相同的 FormControl
实例绑定到多个组件上,这让我很不舒服。如果你允许我提出一个建议,另外 解决了你的问题,即初始值没有在 FormControl
说明:你为什么不通过创建一个 "RadioGroupControl "来利用你的组件,只是为了与表单一起使用,这样你就可以将一个 "RadioGroupControl "关联起来。FormControl
组,而不是用单个控件来做。
你可以做什么
LbRadioButtonGroupComponent
它的模板将是一个非常简单的模板。
selector: 'lb-radio-group-control',
template: '<ng-content></ng-content>'
就像选择器说的那样,这个组件应该只用于在表单中对单选按钮进行分组。它应该只是作为一个包装器。
在它的类型脚本中,抓住RadioButtons的所有实例。
@ContentChildren(RadioButtonComponent, { descendants: true })
_radioButtons: QueryList<RadioButtonComponent>;
然后在每个实例中订阅事件发射器。RadioButtonComponent
. 你需要发出的不仅仅是一个布尔值,这样才会有 LbRadioButtonGroupComponent
可以设置正确的单选按钮 checked
国到 true
当你得到一个传入的值(由主机用 setValue()
, patchValue()
,或者类似的东西)。) 我建议 RadioButtonChange
属性,包含2个属性。target
(被点击的 input
)和 value
一个方便的属性,你想去掉就去掉)。这样我们就有了。
ngAfterViewInit() {
const observableList: Observable<RadioButtonChange>[] = [];
this._radioButtons.map((rb: RadioButtonComponent) =>
observableList.push(rb.checkBoxClick));
merge(...observableList)
.pipe(
filter(Boolean),
takeUntil(this._destroy$)
)
.subscribe((value: any) => {
this._onTouch();
this._onChange(value ? value.value : null);
});
}
那么我们只需要一个方法来设置当前哪个按钮被选中。这里的问题只是一个时间问题,因为我们并不知道什么时候会调用这个方法来设置一个值,我们必须确保我们的 QueryList
已经执行,并且 this._radioButtons
被填充。一旦我们确定发生了这种情况,下面的方法应该将右边的单选按钮设置为 checked
:
private _setGroupValue(value: any) {
this._radioButtons.forEach(
rb => (rb.radioButton.nativeElement.checked =
rb.radioButton.nativeElement.value === value)
);
}
RadioButtonComponent
与 RadioButtonGroupComponent
当在一个表格中把它们作为一组使用时一旦我们有了这些部件,我们就可以像这样使用我们的组件。
<form [formGroup]="radioButtonForm">
<lb-radio-group-control formControlName="gender">
<p lb-radio-button [lbValue]="'Male'"
[lbRole]="'success'">
Male success radio button
</p>
<p lb-radio-button [lbValue]="'Female'"
[lbRole]="'info'">
Female info radio button
</p>
</lb-radio-group>
<div lb-button (buttonClick)="onSubmit()"
type="submit"
lbType="primary">Submit Form</div>
</form>
因为我们已经拥有了 lb-radio-button
的,不需要在它们上设置名称:我们可以在 LbRadioButtonGroupComponent
. 当然,你可以这样做,如果你设置了名称,或者给每个单选按钮设置了不同的名称(误),都没有关系。
在Stackblitz上的代码中,你会发现一个更完整的代码,包含一些验证,比如检查组内是否没有任何的 RadioButtonComponent
拘泥于 FormControl
或开发者是否忘记绑定 LbRadioButtonGroupComponent
到 FormControl
.
好吧,这只是一个整体的想法,以避免绑定相同的。FormControl
到模板中的几个组件。它并不完整,还需要诸如表单验证、表单控制禁用,以及能够通过一个 @Input() value
(我在演示中就开始写了,但我很急,我想你已经明白了)。
不要在lbValue setter里面调用writeValue,它会覆盖FormControl设置的值。
@Input lbValue;
当自定义控件的值发生变化时,你必须调用存储的onChange回调函数,才能将值传播到父表单。
onClick($event): boolean {
if (this.lbDisabled) {
return false;
}
this.onChange($event.target.value);
this.onTouched();
this.checkBoxClick.emit($event.target.value);
}