Dado un elemento de input simple, puedo hacer esto:
<input [(ngModel)]="name" /> {{ name }}Esto no funciona para mis elementos personalizados:
<my-selfmade-combobox [(ngModel)]="name" values="getValues()" required></my-selfmade-combobox>¿Cómo puedo implementarlo?
[(ngModel)]="item" es una abreviatura de [ngModel]="item" (ngModelChange)="item = $event"
Eso significa que si desea agregar una propiedad de enlace bidireccional a su componente, por ejemplo
<app-my-control [(myProp)]="value"></app-my-control>Todo lo que necesita hacer en su componente es agregar
@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>(); El @Input manejará las entradas de escritura y para escribir un nuevo valor de vuelta al padre, simplemente llame a this.myPropChange.emit("Awesome") (Puede poner el emit en un setter para su propiedad si solo quiere hacer asegúrese de que se actualice cada vez que cambie el valor).
Puede leer una explicación más detallada de cómo/por qué funciona aquí .
Si desea usar el nombre ngModel (porque hay directivas adicionales que se vinculan a elementos con ngModel ), o esto es para un elemento FormControl en lugar de un componente (también conocido como, para usar en un ngForm ), entonces deberá jugar con el ControlValueAccessor . Puede leer aquí una explicación detallada para crear su propio FormControl y por qué funciona.
Si realmente necesita [(ngModel)] (que admite ngForm , a diferencia del enfoque [(myProp)] ), creo que este enlace responderá su pregunta:
Necesitamos implementar dos cosas para lograr eso:
ControlValueAccessor personalizado que implementará el puente entre este componente y ngModel / ngControlEl enlace anterior te da una muestra completa...
Implementé el ngModel una vez para la entrada en mis componentes compartidos y desde entonces puedo extenderlo de manera muy simple.
Sólo dos líneas de código:
providers: [createCustomInputControlValueAccessor(MyInputComponent)]
extends InputComponent
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; } <div class="my-input"> <input [(ngModel)]="model"> </div> 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(); } }