Angular 2:聚焦输入导致'表达式在更改后出现'更改'错误

kam*_*ilk 5 typescript angular2-directives angular

在我的Angular 2应用程序中,我想要一个输入列表.在其中一个内部按Enter将添加一个新输入并立即关注它.这是一个已在本网站上提出过的问题,Eric Martinez提供了一个简洁的答案,通过自定义指令实现了这一点.

他的解决方案基于一个整数的虚拟列表.我在努力使其适应更现实的情况时遇到了困难.我已经分叉了Eric的插件,所以你可以在这里运行代码,但最重要的文件就是这个:

//our root app component
import {Component, Directive, Renderer, ElementRef} from 'angular2/core'

class Person { name: string }

@Directive({
  selector : 'input'
})
class MyInput {
  constructor(public renderer: Renderer, public elementRef: ElementRef) {}

  // It won't work at construction time
  ngOnInit() {
    this.renderer.invokeElementMethod(
      this.elementRef.nativeElement, 'focus', []);
  }
}

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div *ngFor="#input of inputs">
      <input
        (keydown.enter)="add()" 
        [(ngModel)]="input.name"
        type="text"/>
    </div>
  `,
  directives: [MyInput]
})
export class App {
  inputs: Person[] = [{name: 'Alice'}];

  add() {
    var newPerson = new Person();
    newPerson.name = 'Bob';

    this.inputs.push(newPerson);
  }
}
Run Code Online (Sandbox Code Playgroud)

我的数组inputs现在是一个Person对象列表.输入双向绑定到a的name属性Person.<input>现在它被包装在一个内部<div>,因为我希望稍后我会写更多的标记来显示每个Person.

进行这些更改后,该示例仅在第一次按Enter键时起作用 - 带有文本Bob的新输入按预期显示.但是当我第二次尝试按Enter时,我收到一个错误:

angular2.dev.js:23730 Error: Expression 'ngClassUntouched in App@2:6' has changed after it was checked. Previous value: 'true'. Current value: 'false'
    at ExpressionChangedAfterItHasBeenCheckedException.BaseException [as constructor] (angular2.dev.js:7587)
    at new ExpressionChangedAfterItHasBeenCheckedException (angular2.dev.js:4992)
    at ChangeDetector_App_1.AbstractChangeDetector.throwOnChangeError (angular2.dev.js:9989)
    at ChangeDetector_App_1.detectChangesInRecordsInternal (viewFactory_App:143)
    at ChangeDetector_App_1.AbstractChangeDetector.detectChangesInRecords (angular2.dev.js:9874)
    at ChangeDetector_App_1.AbstractChangeDetector.runDetectChanges (angular2.dev.js:9857)
    at ChangeDetector_App_0.AbstractChangeDetector._detectChangesContentChildren (angular2.dev.js:9930)
    at ChangeDetector_App_0.AbstractChangeDetector.runDetectChanges (angular2.dev.js:9858)
    at ChangeDetector_HostApp_0.AbstractChangeDetector._detectChangesInViewChildren (angular2.dev.js:9936)
    at ChangeDetector_HostApp_0.AbstractChangeDetector.runDetectChanges (angular2.dev.js:9861)
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

我在Chrome中运行该示例.我发现使用基于Beta 12版Angular2的Eric Martinez的插件来解决这个问题是最容易的,但我现实世界的应用程序中我得到了相同的错误,目前正在使用Angular 2.0.0.

Gün*_*uer 6

Angular2 不喜欢在更改检测回调期间更改模型(就像ngOnInit()是)。调用ChangeDetectorRef.detectChanges()应该修复它:

class MyInput {
  constructor(public renderer: Renderer, public elementRef: ElementRef
      ,private cdRef:ChangeDetectorRef) {}

  // It won't work at construction time
  ngOnInit() {
    this.renderer.invokeElementMethod(
      this.elementRef.nativeElement, 'focus', []);
    this.cdRef.detectChanges();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我知道了。如果只创建 after 之后的一个元素,这是有道理的。当数组最初已经包含一个值列表时,我不会认为它是一个太好的解决方案。我让它与`setTimeout()`一起工作。不知道为什么它不能与 `detectChanges()` 一起使用,但我想这是因为错误不是来自 `MyInput`,而是来自不受 `detectChanges()` 影响的 `NgModel`。如果你不喜欢 `setTimeout()`,另一种可能有效的方法是注入 `ApplicationRef`(而不是 `ChangeDetectorRef`)并调用它的 `.tick()`(而不是 `detectChanges()`) (4认同)