【问题标题】:Why does the oninput event behave differently in Angular than it does in JavaScript?为什么 oninput 事件在 Angular 中的行为与在 JavaScript 中的行为不同?
【发布时间】:2020-11-19 23:45:41
【问题描述】:

我正在使用 TypeScript 学习 Angular,与 JavaScript 的一些不一致让我感到困扰。这是一个与纯 JavaScript 完美配合的函数(它以编程方式将 minmax 属性设置为输入 - 请不要问我 why I'd want to do that programmatically):

function change_number(input,min,max) {
  if(input.value > max)
    input.value = max;
  else if(input.value < min)
    input.value = min;
}
&lt;input type='number' oninput='change_number(this,1,5)' placeholder='Enter a number' /&gt;

在 Angular 和 TypeScript 中,该函数的行为很奇怪:如果我在输入字段中输入 10,它不会重置为 5,直到我输入另一个数字,这意味着该值仅在 之后读取 input 事件(而不是 on-input - 不知道这是否有意义)。更奇怪的是它在keydownkeyup 事件中运行良好。为什么会有这种行为?它是否与 Angular 将事件绑定到输入的方式相关联?我有一种感觉,这将有助于我更好地理解 Angular 与 NgModel 的绑定机制

仅供参考,这是我在 Angular 中调用函数的方式(使用 Ionic 框架) - 我使用 [(ngModel)] 中的绑定 quantity 作为输入值:

<ion-input type='number' (input)='change_numbers(1,5)' [(ngModel)]='quantity'></ion-input>

【问题讨论】:

  • 这个参数似乎是多余的。最小值和最大值也可以是属性,而不是您手动设置值。 w3schools.com/tags/att_input_type_number.asp
  • (input)='change_numbers(1,5) ,这里你应该传递3个参数吧?
  • @TechnoTech 没有必要,因为您可以通过 `[(ngModel)] 获取输入的值。 @John,请查看我的链接,了解为什么我以编程方式而不是使用属性。它在 Angualr 中不起作用,被报告为错误,但我不确定
  • 是的,没错,我以为您使用的是相同的功能。让我检查一下,我将为您的解决方案创建一个链接

标签: javascript html angular typescript


【解决方案1】:

试试这个,效果很好,如果这不是你想要实现的,请告诉我

stackblitz

html

<input type='number' (change)='change_numbers(1,5)' [(ngModel)]="quantity">

javascript

  change_numbers(min,max) {
   if(this.quantity > max)
     this.quantity = max;
   else if(this.quantity < min)
     this.quantity= min;
 }

【讨论】:

  • 您的代码可以工作 onChange,而不是 oninput,这是我的问题,甚至 onkeydownonkeyup 也不能工作
  • @che-azeh - 如果我成功了&lt;input type='number' (input)='change_numbers(1,5)' [(ngModel)]="quantity"&gt;
【解决方案2】:

Angular 框架的行为完美无缺。是我们有点糊涂了。

Angular 处理表单的方式有点不同。有两种方法可以在 Angular 中构建表单 -

  • 反应式(同步)
  • 模板驱动(异步)

它们之间的主要区别在于上述同步/异步行为。简单来说,我们可以这么说。

  • 同步 - 在数据更改期间。
  • 异步 - 数据更改后。

x

<ion-input type='number' (input)='change_numbers(1,5)' [(ngModel)]='quantity'></ion-input>

以上一种是模板驱动的方法。这里我们使用[(ngModel)],只有在数据发生变化后才会更新。

为了制作一个反应式输入字段,请使用以下代码:-

在 app.component.ts 文件中

import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

@Component({
  selector: 'dd-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  form: FormGroup;
  min = 0;
  max = 5;

  constructor(private fb: FormBuilder) {
    this.buildForm();
  }

  buildForm(): void {
    this.form = this.fb.group({
      numberInput: ''
    });

    this.form.get('numberInput').valueChanges.pipe(distinctUntilChanged()).subscribe(_ => {
      if (_) {

        if (_ > this.max) {
          this.form.get('numberInput').setValue(5);
        }
        if (_ < this.min) {
          this.form.get('numberInput').setValue(0);
        }

      } else {
        this.form.get('numberInput').reset('');
      }
    });
  }
}

在 app.html 中(这里我发布了 2 种表达方式。)

  <form [formGroup]="form">
    <!-- <input type='number' [min]='0' [max]='5' formControlName="numberInput" /> we can also this one, more easy just set value dynamically -->
    <input type='number' formControlName="numberInput" />
  </form>

注意:- 不要忘记导入 ReactiveFormsModule

有关表单的更多信息可以在官方文档中找到:-https://angular.io/guide/forms-overview

【讨论】:

  • 您给定的代码在纯 Javascript 中完美运行。但在 Angular 中,表单的处理方式略有不同。
  • 如果仍然感到困惑,请告诉我。
  • 似乎有点麻烦。如果我必须经历所有这些只是为了获得类似 JavaScript 的行为,我想知道,Angular 从重新发明轮子中获得了哪些额外的好处?感谢您的澄清
  • 乍一看可能比较麻烦。即使我在早期也有同样的感觉。但只有我们开始处理有关 froms 的现实问题。这一切都变得容易了。
  • Angular 获得的主要好处 - 是模块化/可重用代码,可测试且易于扩展功能。
【解决方案3】:

不确定这是否有帮助,但我找到了这些;

how to use oninput in Angular?

oninput not working in Angular. Alternative?

他们似乎经常谈论使用(input);你试过了吗?

在 google 上阅读有关此问题的信息,如果您使用 Angular,您似乎必须做一些“Angular 方式”或奇怪的事情,例如您试图寻求答案的事情发生。

正如 Mandolorian 的 Kuiil 所说; “就是这样”

【讨论】:

    【解决方案4】:

    要理解它为什么会这样,首先你需要熟悉两个基本概念:

    1. “盒子里的香蕉”语法[(ngModel)]="quantity" 只不过是转换为[ngModel]="quantity" (ngModelChange)="quantity = $event" 的糖语法
    2. 在 Angular 中,默认情况下会在调用堆栈的末尾触发更改检测(这可以通过 zone.js 实现)。

    有了这些知识,你就能明白这里到底发生了什么:

    stackblitz

    1. 您在输入中键入 4。
    2. onNgModelChange 被触发,quantity 设置为 4input(更具体地说,ngModel 指令)的内部 model 值仍然等于 undefined
    3. change_numbers 被调用,quantity 没有改变。
    4. 这是调用栈的结尾(注意ngModelChangechange_numbers 都在一个调用栈中调用,因为角度处理事件的方式)。执行变化检测。因为quantity4 now)绑定到ngModelundefined now),所以 Angular 检测到需要更新 UI(当然是因为 undefined != 4)。
    5. 更新已执行,一切正常。

    1. 您输入下一个数字 - 8
    2. onNgModelChange 被触发,quantity 设置为 48input(更具体地说,ngModel 指令)的内部 model 值仍然等于 4
    3. change_numbers 被调用,quantity 变为5
    4. 这是调用堆栈的结尾。执行变化检测。因为quantity (5 now) 绑定到ngModel (4 now),所以 Angular 检测到需要更新 UI(当然是因为 5 != 4)。
    5. 更新已执行,一切正常。

    1. 您输入下一个数字 - 7
    2. onNgModelChange 被触发,quantity 设置为 57input(更具体地说,ngModel 指令)的内部 model 值仍然等于 5
    3. change_numbers 被调用,quantity 被更改为5
    4. 这是调用堆栈的结尾。执行变化检测。因为quantity(现在5)绑定到ngModel(现在也是5),所以angular 不会检测到需要更新UI(因为5 == 5 当然)。
    5. 未执行更新,UI 仍然陈旧。

    解决方案可能是在 onNgModelChange 方法中调用 detectChanges。它会起作用,因为此时我们将更新ngModel 的内部model 值(即使它远高于5)。因此,即使我们接下来将值减小到 5,Angular 仍然会检测到需要更新 UI。

    我希望这能解释一切。如果您有一些问题,请随时告诉我。干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-07
      • 2021-04-22
      • 1970-01-01
      • 2010-12-28
      • 2021-01-29
      • 1970-01-01
      • 2016-01-01
      • 1970-01-01
      相关资源
      最近更新 更多