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

Posted

技术标签:

【中文标题】Angular2动态输入字段在输入更改时失去焦点【英文标题】:Angular2 Dynamic input field lose focus when input changes 【发布时间】:2017-07-08 10:59:05 【问题描述】:

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

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

我的组件中有一个向字段添加新值的函数。

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

值和按钮在我的 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>

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

【问题讨论】:

how to use track by inside ngFor angular 2的可能重复 【参考方案1】:

当数组是原始类型时会发生这种情况,在您的情况下是 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>

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

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

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

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

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

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

【讨论】:

在我的例子中,我不是在迭代一个基元数组,而是一个对象数组(实际上是一个 FormArray),我仍然遇到同样的问题。即便如此,我还是按照@AJT_82 的建议解决了问题 @AlexisJoséBravoLlovera 很高兴听到它有效并且对您有所帮助! formarray 似乎发生了某种事情,我自己也不知道原因,因为我们确实在处理对象,类似的问题:***.com/questions/44445676/… 你先生是个英雄。谢谢。 @AJT82 非常感谢!这对我帮助很大,我一直在努力奋斗【参考方案2】:

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

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

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

export ThingComponent 
  ...

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

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

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

在我的例子中,简单的解决方案是缓存 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] 
    )
  

如果cachedThings 可能需要更改,则需要手动更新,以便更改检测器触发重新渲染。

【讨论】:

【参考方案3】:

当您输入一些文本时,角度 ngOnChange 侦听器将运行,因此 ngFor 索引将重新呈现并且焦点将丢失。为了避免这个问题,可以将 trackFn 添加到 ngFor。有关该主题的更多详细信息,请参阅https://angular.io/api/core/TrackByFunction。在您的问题的代码解决方案下方:

在您的 html 代码中定义 ngFor 一个 trackFn 函数,该函数将对应于 .ts 文件中声明的 trackByFn 函数。

    <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>

并在ts文件中声明上面提到的trackByFn函数:

trackByFn(i: number, items: any) 
return index //returning the index itself for avoiding ngFor to change focus after ngModelChange

【讨论】:

以上是关于Angular2动态输入字段在输入更改时失去焦点的主要内容,如果未能解决你的问题,请参考以下文章

打字时 输入框不时失去焦点 非常郁闷

更改为多行后文本输入失去焦点

输入在vue中失去焦点时如何执行功能

当项目更改时,CoreData 绑定的 NSTableView 会失去输入焦点,但前提是已排序

编辑值时输入失去焦点。使用 ngFor 和 ngModel。角5

在本机反应中单击 TextInput 字段外部时失去焦点并关闭键盘?