简体   繁体   English

Angular4:防止输入更改时重新呈现组件

[英]Angular4: Prevent rerendering component on input change

I've been struggling with some stuff in Angular4. 我一直在努力解决Angular4中的一些问题。 Please consider this Plunker: https://embed.plnkr.co/Sh4LaBtXOfxTzeL996jb/ 请考虑这个Plunker: https ://embed.plnkr.co/Sh4LaBtXOfxTzeL996jb/

It's a simple app which has a list of 3 items. 这是一个简单的应用程序,有3个项目的列表。 It displays those 3 items in a subcomponent that lets the user edit the item. 它显示子组件中允许用户编辑项目的这3个项目。

I want to update the state on every keystroke (keyup). 我想在每次击键(keyup)上更新状态。 As I emit the new value, the data in the parent component (App) is updated, which causes a rerender of all the item subcomponents, which in turn causes the input field stop being focussed (as it is replaced). 当我发出新值时,父组件(App)中的数据会更新,这会导致所有项子组件的重新渲染,从而导致输入字段停止聚焦(因为它被替换)。

That means the user can only type a single character before needing to refocus the input. 这意味着用户只能在需要重新聚焦输入之前键入单个字符。

Is there any way to prevent the rerender / keep the focus on the input or a better way to set it up alltogether? 有没有办法阻止重新投入/保持对输入的关注或更好的方式来设置它?

As a temporary fix for this I'm now registering what field has been changed in localStorage and on ngAfterViewInit I'm resetting the focus... which works but is ugly. 作为临时解决方案,我现在正在注册localStorage和ngAfterViewInit中已更改的字段我正在重置焦点......这有效但很难看。 I feel there should be a better way? 我觉得应该有更好的方法吗?

(In the Plunker I've setup a very simple update but in my real app I'm using firebase, subscribing to the list info which gives me the list as a whole when it emits. When that happens I set this.list to the data that's emitted, which causes the rerender.) (在Plunker我设置了一个非常简单的更新,但在我的真实应用程序中我使用firebase,订阅列表信息,它在发出时给我整个列表。当发生这种情况时,我将this.list设置为发出的数据,导致重新渲染。)

Thanks! 谢谢!

You could also use the ngFor track by function to prevent rerendering. 您还可以使用ngFor track by函数来防止重新渲染。 When you use track by, Angular recreates DOM nodes when the specified attribute changes and only then, otherwise it reuses the DOM node and changes it. 当您使用track by时,Angular会在指定的属性更改时重新创建DOM节点,然后再重新使用DOM节点并更改它。

Info about trackBy 有关trackBy的信息

you can import ChangeDetectorRef and manually disable / re-enable changes for a specific component as needed. 您可以导入ChangeDetectorRef并根据需要手动禁用/重新启用特定组件的更改。

 import { ... other stuff... , ChangeDetectorRef } from '@angular/core'

And then in the component 然后在组件中

 constructor( ... other stuff... , private cdr: ChangeDetectorRef) { ... }

 ngOnInit() { 
      this.cdr.checkNoChanges();
  }

That can cause all sort of view wackiness though, so you may just take other commenters suggestion and worry about preventing the focus change, rather than disabling change detection altogether. 这可能导致所有类型的视图古怪,所以您可能只是采取其他评论者的建议并担心防止焦点更改,而不是完全禁用更改检测。 You could also try setting change detection to OnPush mode, which would be less drastic. 您也可以尝试将更改检测设置为OnPush模式,这样可以减少激烈程度。

 import { ChangeDetectionStrategy ...otherstuff } '@angular/core'

and then use it in the component metadata of the top-most component you need to stop automatically propagating changes downward 然后在最顶层组件的组件元数据中使用它,您需要停止自动向下传播更改

@Component({
   selector: 'some-name',
   changeDetection: ChangeDetectionStrategy.OnPush,
   template: ' etc..'

UPDATE: 更新:

 doUpdate(data)
  {
    //no need to update the whole list, only the item will do the trick!
      this.list.items[data.id].name = data.newVal;
  }

The problem is that the list item was generated each time thus the DOM was updated also, so the focus was lost. 问题是每次都生成列表项,因此DOM也被更新,因此焦点丢失了。

Plunker Plunker

Old answer: 老答案:

This will take care of the focus changing: 这将关注焦点的变化:

  doUpdate(data)
  {
   data.preventDefault();
    ......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM