使用 ControlValueAccessor 的单选按钮值选择不正确 (FormGroup/FormControl)

Incorrect Radio-Button's Value Selection using ControlValueAccessor (FormGroup/FormControl)

我无法正确选择单选按钮并停留在那里。

1) 它不记得它的价值并留在那里 2) 它被取消选中并跳转到不同的单选按钮组。

生产。

1) Select 性别(有效)。 2) Select 一种食物(未选择性别,选择了错误的饮料,但正确选择了食物)

[App.ts]

import { Component, NgModule } from '@angular/core';
import { FormGroup, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule }  from '@angular/platform-browser';

import { HtmlRadio1, IHtmlRadioOption1 } from './src1/HtmlRadio1';

@Component({
    moduleId: module.id,  
    selector: 'app',
    templateUrl: 'App.template.html'
})
export class App {
    _genderOptions: IHtmlRadioOption1[] = <IHtmlRadioOption1[]>[
        <IHtmlRadioOption1>{ value: 'M', label: 'Male' },
        <IHtmlRadioOption1>{ value: 'F', label: 'Female' },
        <IHtmlRadioOption1>{ value: 'N', label: 'Neuter' }
    ];
    _foodOptions: IHtmlRadioOption1[] = <IHtmlRadioOption1[]>[
        <IHtmlRadioOption1>{ value: '0', label: 'Apple' },
        <IHtmlRadioOption1>{ value: '1', label: 'Banana' },
        <IHtmlRadioOption1>{ value: '2', label: 'Bread' }
    ];
    _drinkOptions: IHtmlRadioOption1[] = <IHtmlRadioOption1[]>[
        <IHtmlRadioOption1>{ value: '0', label: 'Coke' },
        <IHtmlRadioOption1>{ value: '1', label: 'Milk' },
        <IHtmlRadioOption1>{ value: '2', label: 'Coffee' }
    ];

    _form: FormGroup = new FormGroup({
        gender: new FormControl(),
        food: new FormControl(),
        drink: new FormControl()
    });
}

@NgModule({
    declarations: [App, HtmlRadio1],
    entryComponents: [App, HtmlRadio1],
    imports: [FormsModule, ReactiveFormsModule, BrowserModule],
    bootstrap: [App, HtmlRadio1]
})
export class TestModule {
}

[App.template.html]

<form [formGroup]="_form">
    <div>
        <span>Gender</span>
        <span><htmlRadio1 formControlName="gender" [options]="_genderOptions"></htmlRadio1></span>
    </div>
    <div>
        <span>Food</span>
        <span><htmlRadio1 formControlName="food" [options]="_foodOptions"></htmlRadio1></span>
    </div>
    <div>
        <span>Drink</span>
        <span><htmlRadio1 formControlName="drink" [options]="_drinkOptions"></htmlRadio1></span>
    </div>
</form>

[HtmlRadio1.ts]

import { Component, Input, forwardRef, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR, NgControl, ControlValueAccessor } from '@angular/forms';

const CONTROL_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => HtmlRadio1), multi: true };

export class HtmlInput1 implements ControlValueAccessor {
    private _value: string;
    get value(): string {
        return this._value;
    }
    @Input() set value(val: string) {
        this._value = val;
        this.onChange(val);
    }
    onChange = (_: any) => { };
    onTouched = () => { };
    registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
    registerOnTouched(fn: () => void): void { this.onTouched = fn; }
    writeValue(obj: any): void {
        this.value = obj;
        //this.ngModel.valueAccessor.writeValue(obj);
    }
    protected ngModel: NgControl;

    /** @internal */
    inputId = 'designer_' + Math.random().toString().substr(2);
}
export interface IHtmlRadioOption1 {
    label: string;
    value: string;
}

@Component({
    selector: 'htmlRadio1',
    moduleId: module.id,
    templateUrl: 'HtmlRadio1.template.html',
    providers: [CONTROL_VALUE_ACCESSOR]
})
export class HtmlRadio1 extends HtmlInput1 {
    @ViewChild(NgControl) set ngControl(value: NgControl) { this.ngModel = value; }

    @Input('options') options: IHtmlRadioOption1[] = [];
}

[HtmlRadio1.template.html]

<span>  <!--  ngDefaultControl -->
    <div *ngFor="let opt of options">
        <input type="radio" [attr.id]="inputId" [attr.name]="inputId" [(ngModel)]="value" [value]="opt.value" checked="(value === opt.value)" /> {{ opt.label }}
    </div>
<span>

{{ value | json }}

您没有向 RadioControlValueAccessor 指令提供 name 属性,因此 angular 认为您所有的无线电控制都属于名称为 [=15 的同一个组=] 并通过调用 RadioControlRegistry.select

正确地尝试 select/unselect
select(accessor: RadioControlValueAccessor) {
  this._accessors.forEach((c) => {
    if (this._isSameGroup(c, accessor) && c[1] !== accessor) {
      c[1].fireUncheck(accessor.value);
    }
  });
}

要解决它你需要打开HtmlRadio1.template.html文件并替换

[attr.name]="inputId"

[name]="inputId"