【问题标题】:How to detect a value change on an input when it is dynamically updated (Angular 6)如何在动态更新时检测输入的值变化(Angular 6)
【发布时间】:2019-03-07 16:00:18
【问题描述】:

我正在使用自定义指令和自定义管道对文本输入进行货币格式化。它适用于任何类型的直接用户输入(焦点、模糊、按键)。但是,当值动态更改时,我似乎无法捕获更改事件。我也找不到可靠的主机侦听器事件列表,也不知道如何捕获输入的任何事件(因此无法看到正在发生的事件,如果有的话)。

动态地,该值是用patchValue设置的,我已经将emitEvent设置为true,但这似乎什么也没做(我认为默认情况下它是真的):

myInput.patchValue({content: currentContent}, { emitEvent: true });

我可以在使用 patchValue 设置内容值之前重写货币格式,但这不利于可重用性。

这是我的指令:

import { Directive, HostListener, ElementRef, OnInit } from '@angular/core';
import { CurrencyPipe } from '../pipes/currency.pipe';

@Directive({
    selector: '[appCurrency]'
})
export class CurrencyDirective implements OnInit {

constructor(
    private elementRef:ElementRef,
    private formatcurrencypipe:CurrencyPipe
) { }

ngOnInit(){
    //this.elementRef.nativeElement.value = this.formatcurrencypipe.transform(this.elementRef.nativeElement.value);
}

@HostListener("change", ["$event.target.value", "$event"]) onChange(value, event) {
    //this.elementRef.nativeElement.value = this.formatcurrencypipe.parse(value);
}

@HostListener("valueChange", ["$event.target.value", "$event"]) onValueChange(value, event) {
    console.log('in onValueChange');
    //doesn't trigger when the value is changed dynamically
}

@HostListener("focus",["$event.target.value","$event"]) onFocus(value,event) {
    console.log('in focus');
    this.elementRef.nativeElement.value = this.formatcurrencypipe.parse(value);
    if(event.which == 9)
    {
        return false;
    }
    this.elementRef.nativeElement.select();
}

@HostListener("blur", ["$event.target.value"]) onBlur(value) {
    console.log('in blur');
    this.elementRef.nativeElement.value = this.formatcurrencypipe.transform(value);
}

@HostListener('keydown', ['$event']) onKeyDown(event) {
    let e = <KeyboardEvent> event;
    console.log('e.keyCode: ', e.keyCode, e.ctrlKey, e.metaKey);
    //delete, backspace, tab, escape, enter, decimal, period, arrow left, arrow right
    if ([46, 8, 9, 27, 13, 110, 190, 37, 39].indexOf(e.keyCode) !== -1
    || (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) //CTRL + A
    || (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) //CTRL + C
    || (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) //CTRL + V
    || (e.keyCode === 88 && (e.ctrlKey || e.metaKey))) {  //CTRL + X
        //do nothing
        return;
    }

    // Check for number
    if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
        e.preventDefault();
    }
}
}

我在这里添加了堆栈闪电战:https://stackblitz.com/edit/angular-tys9cy

【问题讨论】:

  • 你试过 吗?
  • 刚试了一下,也没有用。我可能在 hostlistener 中没有正确的事件来捕获它。
  • 在您的指令中,您的方法是正确的@HostListener("change", ["$event.target.value", "$event"]) onChange(value, event) {}。在您的管道中,您应该将转换放在 transform() 方法中,它会自动更改。
  • 转换在transform() 方法中,但是当值动态更改时发生的任何事件都不会被主机侦听器捕获。不知道是不是和patchValue有关。
  • @KatharineOsborne Forked StackBlitz 看看

标签: angular


【解决方案1】:

FormGroupFormControl 这样的反应式表单实例有一个valueChanges 方法,它返回一个observable,它发出最新的值。它不会发出 DOM 事件。
解决方案

而不是 valueChange 绑定到 ngModelChange,这将在两个事件上触发,即当 formControl 在 View 中或通过 Model 更新时。

@HostListener("ngModelChange", [ "$event"]) onNgModelChange(value) {
         console.log(value)
    this.elementRef.nativeElement.value = this.formatcurrencypipe.transform(value);
}

Working StackBlitz

【讨论】:

  • ngModelChange 在 keydown 之后触发,因此在再次转换之前您不能输入多个键。
  • @KatharineOsborne 您可以使用 Rxjs debounceTime 如果您无法找出解决方案,请尝试一下,我会帮助您
  • 是的,我不知道如何使用 debounceTime。我不确定这是否合适,因为用户可能会在完成输入之前暂停(在项目的上下文中他们可能需要做很多心算)。我设置了一个数据值来捕获焦点状态,当它这样做时,我不能再正确地应用管道。反正感觉很不棱角。
  • 天哪,我刚刚意识到我在模糊和焦点上都将焦点标志设置为 true facepalm
【解决方案2】:

根据@vikas 的回答,我进行了修改,使其仅在动态设置值时使用ngModelChange 更新,而不是在用户编辑时更新(因为ngModelChange 对于我的需要来说太包容了):

@HostListener("ngModelChange", [ "$event"]) onNgModelChange(value) {
    //when value changes dynamically
    if (this.elementRef.nativeElement.dataset.isfocused == 'false') {
        console.log('is not focused');
        this.elementRef.nativeElement.value = this.formatcurrencypipe.transform(value);
    } else {
        console.log('is focused');
    }
}

@HostListener("focus",["$event.target.value","$event"]) onFocus(value,event) {
    this.elementRef.nativeElement.dataset.isfocused = true;
    console.log('isfocused: ', this.elementRef.nativeElement.dataset);
    this.elementRef.nativeElement.value = this.formatcurrencypipe.parse(value);
    if(event.which == 9)
    {
        return false;
    }
    this.elementRef.nativeElement.select();
}

@HostListener("blur", ["$event.target.value"]) onBlur(value) {
    this.elementRef.nativeElement.dataset.isfocused = false;
    this.elementRef.nativeElement.value = this.formatcurrencypipe.transform(value);
}

然后输入:

<input appCurrency data-isfocused="false" type="text" class="form-control number" formControlName="myInput" />

使用数据属性似乎非常不合时宜:-(

【讨论】:

    猜你喜欢
    • 2020-05-30
    • 2019-01-02
    • 1970-01-01
    • 2020-07-24
    • 2019-02-09
    • 1970-01-01
    • 2019-07-14
    • 2019-07-09
    • 2018-06-13
    相关资源
    最近更新 更多