Javascript Angular2 动态输入字段在输入更改时失去焦点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42322968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:03:52  来源:igfitidea点击:

Angular2 Dynamic input field lose focus when input changes

javascriptangularangular2-formsngforangular2-ngmodel

提问by Servietsky

I'm making a dynamic form. A Fieldhas a list of values. Each value is represented by a string.

我正在制作一个动态表格。AField有一个值列表。每个值都由一个字符串表示。

export class Field{
    name: string;
    values: string[] = [];
    fieldType: string;
    constructor(fieldType: string) {this.fieldType = fieldType;}
}

I have a function in my component which adds a new value to the field.

我的组件中有一个函数可以为该字段添加一个新值。

addValue(field){
    field.values.push("");
}

The values and the button are displayed like this in my HTML.

值和按钮在我的 HTML 中是这样显示的。

<div id="dropdown-values" *ngFor="let value of field.values; let j=index">
    <input type="text" class="form-control" [(ngModel)]="field.values[j]" [name]="'value' + j + '.' + i"/><br/>
</div>
<div class="text-center">
    <a href="javascript:void(0);" (click)="addValue(field)"><i class="fa fa-plus-circle" aria-hidden="true"></i></a>
</div>

As soon as I write some text in an input of a value, the input loses focus. If I add many values to a field and I write a character in one the values input, the input lose focus and the character is written in every input.

一旦我在一个值的输入中写入一些文本,输入就会失去焦点。如果我向一个字段添加许多值,并且我在输入的值中写入一个字符,则输入会失去焦点并且该字符会写入每个输入中。

回答by AJT82

This happens when the array is a primitive type, in your case a Stringarray. This can be solved by using TrackBy. So change your template to match the following:

当数组是原始类型时会发生这种情况,在您的情况下是String数组。这可以通过使用来解决TrackBy。因此,更改您的模板以匹配以下内容:

<div *ngFor="let value of field.values; let i=index; trackBy:trackByFn">
    <input type="text" [(ngModel)]="field.values[i]"  /><br/>
</div>
<div>
    <button (click)="addValue(field)">Click</button>
</div>

and in the ts file add the function trackByFn, which returns the (unique) indexof the value:

并在 ts 文件中添加函数trackByFn,它返回值的(唯一)index

trackByFn(index: any, item: any) {
   return index;
}

This is a linkabout the same issue, except the issue is for AngularJS, but the problem corresponds yours. Most important excerpt from that page:

这是一个关于同一问题的链接,除了问题是针对 AngularJS 的,但问题与您的问题相对应。该页面最重要的摘录:

You are repeating over an array and you are changing the items of the array (note that your items are strings, which are primitives in JS and thus compared "by value"). Since new items are detected, old elements are removed from the DOM and new ones are created (which obviously don't get focus).

您正在重复数组并更改数组的项目(请注意,您的项目是字符串,它们是 JS 中的基元,因此“按值”进行比较)。由于检测到新项目,旧元素会从 DOM 中删除并创建新元素(显然不会获得焦点)。

With TrackByAngular can track which items have been added (or removed) according to the unique identifier and create or destroy only the things that changed which means you don't lose focus on your input field :)

使用TrackByAngular 可以根据唯一标识符跟踪已添加(或删除)的项目,并仅创建或销毁更改的内容,这意味着您不会失去对输入字段的关注:)

As seen in the link you can also modify your array to contain objects which are unique and use [(ngModel)]="value.id"for example, but that's maybe not what you need.

如链接中所示,您还可以修改数组以包含[(ngModel)]="value.id"例如唯一和使用的对象,但这可能不是您需要的。

回答by t.888

This was happening to me when I was iterating over an object's keys and values by using a helper function:

当我使用辅助函数迭代对象的键和值时,这发生在我身上:

<div *ngFor="let thing of getThings()" [attr.thingname]="thing.key">
  ... {{ applyThing(thing.value) }}
</div>

In my component I was returning an array of objects containing key/value pairs:

在我的组件中,我返回了一个包含键/值对的对象数组:

export ThingComponent {
  ...

  //this.things = { a: { ... }, b: { ... }, c: { ... } }

  public getThings() {
    return Object.keys(this.things).map((key) => {
      return {key: key, value: this.things[key] }
    })
  }
}

The answer given by @AJT_82 definitely works exactly as advertised. However in my case the specific issue was that the helper function, getThings(), was returning a new list of objects every time. Even though their content was the same, the objects themselves were regenerated on every call to the function (which was happening during change detection) and hence, to the change detector, they had different identities, and the form was regenerated on every model change.

@AJT_82 给出的答案绝对像宣传的那样有效。但是,就我而言,具体问题是辅助函数getThings()每次都返回一个新的对象列表。即使它们的内容相同,对象本身在每次调用函数时都会重新生成(在更改检测期间发生),因此,对于更改检测器,它们具有不同的身份,并且在每次模型更改时都会重新生成表单。

The simple solution in my case was to cache result of getThings()and use that as the iterator:

在我的情况下,简单的解决方案是缓存结果getThings()并将其用作迭代器:

<div *ngFor="let thing of cachedThings" [attr.thingname]="thing.key">
  ... {{ applyThing(thing.value) }}
</div>

...

...

export ThingComponent {
  public cachedThings = getThings()
  ...

  //this.things = { a: { ... }, b: { ... }, c: { ... } }

  private getThings() {
    return Object.keys(this.things).map((key) => {
      return {key: key, value: this.things[key] }
    })
  }
}

In cases where cachedThingsmight need to vary, it'll need to be updated manually so the change detector will trigger re-rendering.

cachedThings可能需要变化的情况下,需要手动更新,以便更改检测器触发重新渲染。