【问题标题】:Detect when input value changed in directive检测指令中输入值何时更改
【发布时间】:2017-06-03 08:10:27
【问题描述】:

我正在尝试检测指令中输入的何时更改。我有以下指令:

    import { ElementRef, Directive, Renderer} from '@angular/core';

    @Directive({
        selector: '[number]',
        host: {"(input)": 'onInputChange($event)'}
    })

    export class Number {

        constructor(private element: ElementRef, private renderer: Renderer){

        }
        onInputChange(event){
            console.log('test');
        }
    }

这个指令的问题是它只在有输入时检测,而不是在值以编程方式更改时检测。我使用响应形式,有时我使用patchValue() 函数设置值。如何触发更改功能?

【问题讨论】:

    标签: angular angular-directive angular2-directives


    【解决方案1】:

    您需要创建input 的输入属性,然后使用ngOnChanges 挂钩来判断输入属性何时更改。

    @Directive({
        selector: '[number]'
    })
    export class NumberDirective implements OnChanges {
        @Input() public number: any;
        @Input() public input: any;
    
        ngOnChanges(changes: SimpleChanges){
          if(changes.input){
            console.log('input changed');
          }
        }
    }
    

    Plunkr

    Stackblitz

    【讨论】:

    • ngOnChanges(更改:SimpleChanges)
    • 这需要一个输入指令,它应该使用没有任何依赖关系的主机监听器
    【解决方案2】:

    有一种更好的方法可以检测Input 属性何时发生变化,它被认为是一种最佳做法,它也用于*ngIf implementation

    您只需将关键字set 推迟到Input() 之后,这样您就可以将@Input() 装饰器与setter 结合起来,并且它会在值发生变化时被调用。

    _rows: number;
    @Input() set rows(value: number) {
      if (this.value < 0) {
        console.error('The number of rows must be positive');
        this._rows = 2;
        return;
      }
     
      this._rows = value;
    }
    

    如果要将新值与之前的值进行比较,则必须将变量存储在类属性中,并在第二次调用该方法时检索它:

    private previousValue: any = T;
    
    @Input() set myInputName(value: T) {
      console.log(`Previous value was: ${this.previousValue}`);
      console.log(`New value is: ${value}`);
      this.previousValue = value;  
    }
    

    【讨论】:

    • 你没有回答问题
    • @MattewEon Wtf?这完美地解决了问题,因为它可以检测到何时以编程方式更改输入
    • 目标不是给组件添加一个新的@Input属性,他想检测ngModel属性的变化
    • 使用最新 Angular 7 @Input 样式的好方法。
    • 如果@input变量的名字和指令的名字一样,那么就可以在ngModel上获取watch。例如@Input() set number(value: T) {...} 用法示例是
    【解决方案3】:

    从 Angular 9+ 开始,我可以验证下面的 sn-p 是正确的解决方案。出于多种原因,最好尽可能避免ngOnChanges,而是使用正确的主机侦听器事件。下面的示例将获取keyup 上的当前输入值。您可以根据输入指令的需要轻松自定义此代码 sn-p。

      @Directive({
          selector: '[appMyDirective]',
      })
      export class MyDirective {
        // Add whatever event you want to track here
        @HostListener('keyup', ['$event']) public onKeyup(event: KeyboardEvent): void {
          const value = (event.target as HTMLInputElement).value;
          console.log(value);
        }
      }

    【讨论】:

    • 这很好用,只要记住 HostListener 将触发更改检测,无论您是否实际处理事件/更改任何内容。这可能会影响性能并且即使所有组件都使用 ChangeDetectionStrategy.OnPush 仍然适用。
    【解决方案4】:

    您也可以使用 HostListener。关于 HostListener 的更多信息,您可以通过this link。这是代码。

    import {Directive, ElementRef, HostListener} from '@angular/core';
    
    
    @Directive({
           selector: '[number]'
     })
    
    export class NumberDirective {
    
        @Input() public number: any;
        @Input() public input: any;
    
        constructor(private el: ElementRef) {}
    
        @HostListener('change') ngOnChanges() {
            console.log('test');
        }
    
    }
    

    【讨论】:

    • 'change' 不起作用,'mouseenter','mouseleave' 来自角度示例工作。请测试你的答案。
    • 'change' 至少适用于选择菜单('ngModelChange' 也是如此,您可以通过注入 $event var: @HostListener('ngModelChange', ['$event']) public doStuff(value) { ... } 来获得新值)
    猜你喜欢
    • 2023-03-03
    • 2018-02-07
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 2016-07-07
    • 2022-01-16
    • 1970-01-01
    • 2019-08-02
    相关资源
    最近更新 更多