Estoy usando un método SET para establecer mi valor límite en 'DEFAULT' si alguna vez intentamos establecerlo en una cadena vacía. La entrada de texto enlazado se comporta correctamente en todos los escenarios, EXCEPTO si el campo de texto ya dice 'PREDETERMINADO' y yo "selecciono todo + elimino" ese valor. El valor límite se vuelve a establecer correctamente en 'DEFAULT' inmediatamente, pero el campo de entrada permanece vacío.
Aquí hay un stackblitz que muestra el problema https://stackblitz.com/edit/angular-a9j8tv?file=src%2Fapp%2Fapp.component.html
Si tiene 'DEFAULT' y selecciona todo y elimina, puede ver que la entrada permanece vacía, pero el intervalo que está vinculado al mismo valor muestra correctamente el valor 'DEFAULT' recién restablecido.
¿Por qué pasó esto? ¿Hay un trabajo alrededor?
El problema proviene de ngModel . Que desde el '' valor manipulando a DEFAULT , que es el último valor que ha ngModel , ngModel no se da cuenta del cambio de valor para activar un nuevo evento de cambio de valor.
Cómo solucionarlo;
He asignado el valor cambiado directamente a la variable en el setter antes de la comparación. Luego, establezca un tiempo de espera mínimo para que ngModel pueda actualizar su valor existente. Luego, cuando comparo el nuevo valor y lo vuelvo a cambiar a DEFAULT en el caso de '' , ngModel se da cuenta del cambio de valor y activa el nuevo evento de cambio de valor. Esto actualiza ambas representaciones.
La directiva ngModel usa @Input y @Output para obtener el valor y emitir el evento de cambio. Por lo tanto, vincular una función como setter o getter a una directiva como [ngModel] con la estrategia de detección de cambios predeterminada activaría la función para cada detección de cambios.
Para replicar este error, conecte un console.log en el getter, escriba algún valor y siga presionando la tecla de retroceso en <input> y suéltelo. Podría ver que los mensajes de console.log se siguen imprimiendo.
Error de replicación: Stackblitz
Como se dijo antes, la directiva ngModel usa @Input y, en consecuencia, el gancho ngOnChanges() para obtener cualquier cambio en el valor de la etiqueta <input> . Una cosa importante a tener en cuenta es que ngOnChanges() no se activará si el valor no ha cambiado (1) .
Podríamos intentar dividir el enlace bidireccional [(ngModel)] a la entrada [ngModel] y la salida (ngModelChange) .
export class AppComponent { public testString: string; onChange(value: string) { this.testString = value === '' ? 'DEFAULT' : value; } } <input type="text" [ngModel]="testString" (ngModelChange)="onChange($event)" />Todavía propenso a errores: Stackblitz
Aquí, Ctrl + a + Retroceso cualquier cadena que no sea 'DEFAULT' insertaría 'DEFAULT' como se esperaba. Pero Ctrl + a + Retroceso 'DEFAULT' daría como resultado un cuadro <input> vacío debido al ngOnChanges() discutido anteriormente.
Una forma de lograr el comportamiento esperado es no depender del ngModel ngOnChanges() de la directiva ngModel para establecer el valor, sino hacerlo nosotros mismos manualmente. Para eso, podríamos usar una variable de referencia de plantilla Angular en <input> y enviarla al componente para su posterior manipulación.
export class AppComponent { public testString: string; public onChange(value: string, inputElem: HTMLInputElement) { this.testString = value === '' ? 'DEFAULT' : value; inputElem.value = this.testString; } } <input type="text" #myInput ngModel (ngModelChange)="onChange($event, myInput)" />Ejemplo de trabajo: Stackblitz
Aquí #myInput es la variable de referencia de la plantilla. Si esto se siente extraño, debe saber que usar ngModel para manipular <input> se denomina en sí mismo formularios basados en plantillas . Y es bastante legal manipular la referencia de la plantilla directamente.
Dicho todo esto, en mi opinión, en los casos en que se necesite tal manipulación de entrada, le recomiendo que use los formularios reactivos angulares en su lugar. Proporciona un control más granular sobre la entrada.
(1) ngOnChanges() no se activará si el valor previousValue y el valor @Input del objeto SimpleChange de la variable currentValue respectiva no han cambiado.