首页 > 解决方案 > Angular - 如何绑定到嵌套在子组件中两层深处的单选按钮的输入值?

问题描述

我有一组已制成组件的单选按钮,其父级是一个表单,也是一个组件。父表单由一个名称字段、一个电子邮件字段和一组三个单选按钮问题组成。

父窗体.component.ts

@Component({
    selector: 'parent-form',
    template: `
        <form #myform="ngForm" (ngSubmit)="save(myform)">
            <label>Name</label>
            <input type="text" id="name" name="name" [(ngModel)]="name" />

            <label>Email</label>
            <input type="text" id="email" name="email" [(ngModel)]="email" />

            <label>Radio Question 1</label>
            <radio-buttons [radioText]="radioButtonsText[0]" [radioId]="0"></radio-buttons>

            <label>Radio Question 2</label>
            <radio-buttons [radioText]="radioButtonsText[1]" [radioId]="1"></radio-buttons>

            <label>Radio Question 3</label>
            <radio-buttons [radioText]="radioButtonsText[2]" [radioId]="2"></radio-buttons>
        </form>
    `
})
export class ParentFormComponent implement OnInit {
   name: string = "";
   email: string = "";
   radioSelection1: number = 0;
   radioSelection2: number = 0;
   radioSelection3: number = 0;

   radioButtonText = [
       ['Very Bad', 'Bad', 'Neutral', 'Good', 'Very Good'],
       ['None', 'A Little', 'Somewhat', 'Often', 'Frequent'],
       ['Very Worried', 'A bit worried', 'Neutral', 'generally not worried', 'not worried at all']
   ];

   ngOnInit() {}

   save(form: NgForm) {
       console.log(form.value);
   }
}

单选按钮.component.ts

@Component({
    selector: 'radio-buttons',
    template: `
        <div>
            <label>
                <input type="radio" name="radio + {{ radioId }}" id="option1" value="0" />
                {{ radioText[0] }}
            </label

            <label>
                <input type="radio" name="radio + {{ radioId }}" id="option2" value="1" />
                {{ radioText[1] }}
            </label

            <label>
                <input type="radio" name="radio + {{ radioId }}" id="option3" value="2" />
                {{ radioText[2] }}
            </label

            <label>
                <input type="radio" name="radio + {{ radioId }}" id="option4" value="3" />
                {{ radioText[3] }}
            </label

            <label>
                <input type="radio" name="radio + {{ radioId }}" id="option5" value="4" />
                {{ radioText[4] }}
            </label
        </div>
    `
})
export class RadioButtonComponent {
    @Input() radioText = [];
    @Input() radioId = '';
    constructor() {}
}

现在我的问题是ParentFormComponent,如何“访问”每组单选按钮的点击值?我尝试戴上标签和标签,[(ngModel)]="radioSelection1"但它们都不起作用。radio-buttoninputRadioButtonComponent

我希望能够获取单选按钮的每个选定答案的值,并将其传递到我的后端进行保存。

标签: angular

解决方案


一种方法是使用ControlValueAccessor.

您可以查看有关此主题的这些文章:

另一种方法是利用该viewProviders选项。

例如:

父组件.html

<form #f="ngForm">
  <input ngModel name="test" type="text">

  <app-radio-buttons ctrlName="radioCtrl"></app-radio-buttons>
</form>

<p>
  Form values: {{ f.value | json }}
</p>

单选按钮.component.ts

@Component({
  selector: 'app-radio-buttons',
  templateUrl: './radio-buttons.component.html',
  styleUrls: ['./radio-buttons.component.css'],
  viewProviders: [
    {
      provide: ControlContainer,
      useExisting: NgForm,
    }
  ]
})
export class RadioButtonsComponent implements OnInit {
  @Input() ctrlName: string;
}

单选按钮.component.html

<h3>radio btn component</h3>

value1: <input ngModel [name]="ctrlName" type="radio" value="1">
value2: <input ngModel [name]="ctrlName" type="radio" value="2">

<!-- Setting a default value -->
value3: <input ngModel="3" [name]="ctrlName" type="radio" value="3">

使用Reactive Forms时,您可以遵循相同的模式,但您必须更改NgFormFormGroupDirective.

该解决方案基于如何viewProviders@Host装饰器一起工作。

例如,NgModel指令的构造函数如下所示:

constructor(
    @Optional() @Host() parent: ControlContainer,
    /* ... */
  ) {
  super();
  this._parent = parent;
  /* ... */
}

引用自Angular:嵌套模板驱动的表单

宿主装饰器让我们有机会从为宿主元素声明的 viewProviders 中获取提供者

在这种情况下,宿主元素是<form>元素:

export const formDirectiveProvider: any = {
  provide: ControlContainer,
  useExisting: forwardRef(() => NgForm)
};

@Directive({
  selector: 'form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]',
  providers: [formDirectiveProvider],
  host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
  outputs: ['ngSubmit'],
  exportAs: 'ngForm'
}) { /* ... */ }

来源

如您所见,我们有ControlContainer,可以在 中访问viewProviders

ng-运行演示


推荐阅读