Angular 2 在每次按键时触发的改变事件

424

change事件仅在输入框的焦点改变后才被调用。我该如何使它在每次按键时都触发?

<input type="text" [(ngModel)]="mymodel" (change)="valuechange($event)" />
{{mymodel}}

顺便提一下,第二个绑定会在每次按键时更改。


keypress已被弃用。https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event - jbobbins
13个回答

725

我刚刚使用了事件输入,它的工作效果如下:

在HTML文件中:

<input type="text" class="form-control" (input)="onSearchChange($event.target.value)">

在 .ts 文件中:

onSearchChange(searchValue: string): void {  
  console.log(searchValue);
}

2
我们如何延迟一段时间? - Mahmoud Hboubati
(input) 事件在 Edge 和 IE 浏览器中不受支持。在 Edge 浏览器中有什么替代方法? - Sudhakar
谢谢,非常适合Angular 6。 - bensonissac
1
花了很多时间在变更检测和其他方面。最终,找到了平静。谢谢你! PS:我的问题与Angular [formGroup]有关,在找到这篇文章之前我一直使用(change)。不知道(input)也可以用。 - saberprashant
非常感谢,我注意到(更改)事件在失焦时触发,而这个是在您键入时触发的。 - Royce
@MahmoudHboubati 这可能有点晚,但你可以通过使用setTimeout来延迟搜索,并存储该函数的返回值。每次在再次执行之前,你可以通过clearTimeout来重置延迟执行:if (this.searchDelayHandle) clearTimeout(this.searchDelayHandle); this.searchDelayHandle = setTimeout(() => ..., 1000); - undefined

232

通过拆分 [(x)] 语法的两个部分,即属性数据绑定和事件绑定,使用 ngModelChange:

<input [ngModel]="x" (ngModelChange)="x = $event">
<input type="text" [ngModel]="mymodel" (ngModelChange)="valuechange($event)" />
{{mymodel}}
valuechange(newValue) {
  mymodel = newValue;
  console.log(newValue)
}

对于退格键也起作用。


5
使用香蕉-in-盒子的语法时,只会改变模型,但你无法将某些东西挂钩在更改事件上。 - Giora Guttsait
4
这是关于最佳双向数据绑定的绝佳答案。应该被接受作为答案! - Tk1993
4
退格键未更新模型。 - Karan Garg
6
这个解决方案是正确的。不过需要注意的是,ngModelChange事件在值更新之前就被触发了。因此,这个例子中的'newValue'包含的是没有刚刚按下的键的模型 - 所以你在那里没有更新后的模型。如果你想要最新的模型值,可以使用(keyup)事件。 - dave0688
1
@SateeshKumarAlli,你使用的是哪个版本的Angular?对我来说,在Angular 6.1.3中它可以检测到退格键。 - Jette
显示剩余8条评论

154

(keyup)事件是最佳选择。

让我们看看为什么:

  1. (change) 像你提到的,仅会在输入框失去焦点时触发,因此使用范围受限。
  2. (keypress) 只会在按键时触发,但不适用于某些按键,如退格键。
  3. (keydown) 在每次按下键时触发。因此始终落后一个字符;因为它获取的是在按键被注册之前的元素状态。
  4. (keyup) 是最佳选择,因为它会在每次按键完成时触发,这也包括最近的字符。

所以 (keyup) 是最安全的选择,因为它...

  • 与 (change) 事件不同,可以在每次按键时注册事件
  • 包括 (keypress) 忽略的按键
  • 与 (keydown) 事件不同,没有延迟

7
正如其中一个答案所提到的那样,输入事件非常有效。 keyup 绝对是其中最安全的选项之一,不过,input 事件比 keyup 更为先进。与 input 不同,如果文本框的值通过任何其他方式(例如绑定)更改,则 keyup 将无法工作。 - planet_hunter
2
这应该是被接受和最安全的答案,因为它是本地的并且给你完全的控制权,而且非常具有表现力,因为每个阅读它的人都知道事件何时被触发。 - Florian Leitgeb
2
@ThariqNugrohotomo 不会的。如果你想要这样的东西,请使用(input)。 - Sagar
1
(keyup) 帮我解决了退格键的问题,非常感谢! - theomeli
1
keyup 如其名称所示,仅适用于按键,因此使用 Ctrl+v 粘贴时会被检测到,而使用鼠标上下文菜单粘贴则不会。 - Mart
显示剩余5条评论

40

10
可以工作,但奇怪的是退格键不能被识别为按键? - daniel
23
你可能希望使用 keydownkeyup 代替 keypress。有些键在 keypress 上不会触发。另请参见 https://dev59.com/EW445IYBdhLWcg3wdqOO - Günter Zöchbauer
我已经尝试使用“keydown”,“keyup”和“change”事件,但当输入为“w”时,事件处理程序向我报告空字符串;当输入为“we”时,事件处理程序向我报告输入为“w”。请问这种行为的原因是什么? - forethought
1
很奇怪,但我在这里遇到输入延迟问题,即值直到下一次按键才包含已打的字符。 - Matt Eland
1
keypress已被弃用。https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event - jbobbins
显示剩余2条评论

38
处理这种情况的另一种方法是在组件初始化时使用formControl并订阅其valueChanges,这将允许您使用rxjs操作符来满足高级需求,如执行http请求、应用防抖直到用户完成输入句子、获取最后一个值并忽略之前的值等。
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

@Component({
  selector: 'some-selector',
  template: `
    <input type="text" [formControl]="searchControl" placeholder="search">
  `
})
export class SomeComponent implements OnInit {
  public searchControl: FormControl;
  public debounce: number = 400;

  ngOnInit() {
    this.searchControl = new FormControl('');
    this.searchControl.valueChanges
      .pipe(debounceTime(this.debounce), distinctUntilChanged())
      .subscribe(query => {
        console.log(query);
      });
  }
}

2
这太完美了。在使用异步HTTP请求时,可以减少冗长的噪音。它还已经设置好了更改事件监听器。太棒了!谢谢! - hewstone
1
如果有多个控件,可以使用 FormGroup 应用相同的代码。 - Vikash Kumar

23

保持Angular ngModel同步的秘密事件就是input事件的调用。因此,对于你的问题,最好的答案应该是:

<input type="text" [(ngModel)]="mymodel" (input)="valuechange($event)" />
{{mymodel}}

对我来说可以 @AndreiDiaconescu - KhoPhi
(input) 事件在 Edge 和 IE 浏览器中不受支持。在 Edge 浏览器中有什么替代方法? - Sudhakar

8
<input type="text" (keypress)="myMethod(myInput.value)" #myInput />

归档 .ts

myMethod(value:string){
...
...
}

1
欢迎来到SO Ulric,请解释一下你的代码是如何解决这个问题的。 - CPHPython
keypress已被弃用。https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event - jbobbins

6

对于反应式表单,您可以订阅所有字段的更改或仅订阅特定字段的更改。

获取 FormGroup 的所有更改:

this.orderForm.valueChanges.subscribe(value => {
    console.dir(value);
});

获取特定字段的更改:

this.orderForm.get('orderPriority').valueChanges.subscribe(value => {
    console.log(value);
  });

请注意,它只会在失去焦点时触发。 - Suciu Eus

5

我通过使用以下代码在Angular 11中解决了这个问题:

<input type="number" min="0" max="50" [value]="input.to" name="to"
        (input)="input.to=$event.target.value; experienceToAndFrom()">

experienceToAndFrom() 是我的组件中的一个方法。

附注:我尝试了以上所有解决方案,但都没有起作用。


4

在我的情况下,解决方案是:

[ngModel]="X?.Y" (ngModelChange)="X.Y=$event"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接