87

给定一个简单的input元素,我可以这样做:

<input [(ngModel)]="name" /> {{ name }}

这不适用于我的自定义元素:

<my-selfmade-combobox [(ngModel)]="name" values="getValues()" required></my-selfmade-combobox>

我该如何实施?

4

5 回答 5

66

[(ngModel)]="item"是的简写[ngModel]="item" (ngModelChange)="item = $event"

这意味着如果你想为你的组件添加一个 2-way 绑定属性,例如

<app-my-control [(myProp)]="value"></app-my-control>

您在组件中需要做的就是添加

@Input()
myProp: string;

// Output prop name must be Input prop name + 'Change'
// Use in your component to write an updated value back out to the parent
@Output()
myPropChange = new EventEmitter<string>();

@Input处理写入并将新值写回父级,只需调用this.myPropChange.emit("Awesome")(如果您只想确保每次值更改时都更新它,您可以将发射放入您的属性的设置器中。)

您可以在此处阅读有关其工作方式/原因的更详细说明。


如果您想使用名称ngModel(因为有额外的指令使用 绑定到元素ngModel),或者这是针对FormControl元素而不是组件(AKA,用于在 an 中使用ngForm),那么您将需要使用ControlValueAccessor. FormControl可以在此处阅读有关制作自己的内容及其工作原理的详细说明。

于 2020-01-06T21:10:28.250 回答
50

如果您确实需要(与方法不同,[(ngModel)]它支持),我认为此链接将回答您的问题:ngForm[(myProp)]

我们需要实现两件事来实现这一点:

  • 提供表单组件逻辑的组件。它不需要输入,因为这将由 ngModel 本身提供
  • ControlValueAccessor将实现此组件和ngModel/之间的桥梁的自定义ngControl

上一个链接为您提供了完整的示例...

于 2016-02-02T09:32:44.177 回答
9

我在我的共享组件中实现了ngModel一次输入,然后我可以非常简单地扩展它。

只有两行代码:

  1. providers: [createCustomInputControlValueAccessor(MyInputComponent)]

  2. extends InputComponent

我的输入.component.ts

import { Component, Input } from '@angular/core';
import { InputComponent, createCustomInputControlValueAccessor } from '../../../shared/components/input.component';
@Component({
   selector: 'my-input',
   templateUrl: './my-input-component.component.html',
   styleUrls: ['./my-input-component.scss'],
   providers: [createCustomInputControlValueAccessor(MyInputComponent)]
})
export class MyInputComponent extends InputComponent {
    @Input() model: string;
}

我的输入.component.html

<div class="my-input">
    <input [(ngModel)]="model">
</div>

输入组件.ts

import { Component, forwardRef, ViewChild, ElementRef, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
export function createCustomInputControlValueAccessor(extendedInputComponent: any) {
    return {
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => extendedInputComponent),
        multi: true
    };
}

@Component({
    template: ''
})
export class InputComponent implements ControlValueAccessor, OnInit {
    @ViewChild('input') inputRef: ElementRef;

    // The internal data model
    public innerValue: any = '';

    // Placeholders for the callbacks which are later provided
    // by the Control Value Accessor
    private onChangeCallback: any;

    // implements ControlValueAccessor interface
    writeValue(value: any) {
        if (value !== this.innerValue) {
            this.innerValue = value;
        }
    }
    // implements ControlValueAccessor interface
    registerOnChange(fn: any) {
        this.onChangeCallback = fn;
    }

    // implements ControlValueAccessor interface - not used, used for touch input
    registerOnTouched() { }

    // change events from the textarea
    private onChange() {
        const input = <HTMLInputElement>this.inputRef.nativeElement;
        // get value from text area
        const newValue = input.value;

        // update the form
        this.onChangeCallback(newValue);
    }
    ngOnInit() {
        const inputElement = <HTMLInputElement>this.inputRef.nativeElement;
        inputElement.onchange = () => this.onChange();
        inputElement.onkeyup = () => this.onChange();
    }
}
于 2018-07-19T10:56:44.817 回答
5

第 1 步:添加以下providers属性:

@Component({
    selector: 'my-cool-element',
    templateUrl: './MyCool.component.html',
    styleUrls: ['./MyCool.component.css'],
    providers: [{   // <================================================ ADD THIS
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => MyCoolComponent),
        multi: true
    }]
})

第 2 步:实施ControlValueAccessor

    export class MyCoolComponent implements ControlValueAccessor {
    
      private _value: string;
      // Whatever name for this (myValue) you choose here, use it in the .html file.
      public get myValue(): string { return this._value }
      public set myValue(v: string) {
        if (v !== this._value) {     
          this._value = v;
          this.onChange(v);
        }
      }
    
      constructor() {}
    
      onChange = (_) => { };
      onTouched = () => { };
    
      writeValue(value: any): void {    
        this.myValue = value;
      }
      registerOnChange(fn: any): void {
        this.onChange = fn;
      }
      registerOnTouched(fn: any): void {
        this.onTouched = fn;
      }
      setDisabledState?(isDisabled: boolean): void {
        throw new Error("Method not implemented.");
      }
    
    }

第 3 步:在 html 中,绑定您想要的任何控件myValue


    <my-cool-element [(value)]="myValue">
              <!-- ..... -->
     </my-cool-element>
于 2019-09-13T01:30:51.890 回答
0

您可以自己实现自定义双向绑定。对于角度 10,请参阅官方示例SizerComponent,这里的[(size)]行为就像[(ngModel)]

<app-sizer [(size)]="fontSizePx"></app-sizer>
于 2021-07-24T06:49:37.203 回答