Javascript Angular2 刷新数组推送视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36247016/
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 18:48:38  来源:igfitidea点击:

Angular2 refreshing view on array push

javascriptarraysasynchronousangularsetinterval

提问by Omer Kushmaro

I can't seem to get angular2 view to be updated on an array.push function, called upon from a setInterval async operation.

我似乎无法在 array.push 函数上更新 angular2 视图,从 setInterval 异步操作调用。

the code is from this angular plunkr example of setInterval:

代码来自setInterval 的这个angular plunkr 示例

What i'm trying to do is as follows:

我想要做的是如下:

import {View, Component, bootstrap, Directive, ChangeDetectionStrategy, ChangeDetectorRef} from 'angular2/angular2'

@Component({selector: 'cmp', changeDetection: ChangeDetectionStrategy.OnPush})
@View({template: `Number of ticks: {{numberOfTicks}}`})
class Cmp {
  numberOfTicks = [];
  
  constructor(private ref: ChangeDetectorRef) {
    setInterval(() => {
      this.numberOfTicks.push(3);
      this.ref.markForCheck();
    }, 1000);
  }
}

@Component({
  selector: 'app',
  changeDetection: ChangeDetectionStrategy.OnPush
})
@View({
  template: `
    <cmp><cmp>
  `,
  directives: [Cmp]
})
class App {
}

bootstrap(App);
<!DOCTYPE html>
<html>

<head>
  <title>angular2 playground</title>
  <script src="https://code.angularjs.org/tools/traceur-runtime.js"></script>
  <script src="https://code.angularjs.org/tools/system.js"></script>
  <script src="https://code.angularjs.org/tools/typescript.js"></script>
  <script data-require="jasmine" data-semver="2.2.1" src="http://cdnjs.cloudflare.com/ajax/libs/jasmine/2.2.1/jasmine.js"></script>
  <script data-require="jasmine" data-semver="2.2.1" src="http://cdnjs.cloudflare.com/ajax/libs/jasmine/2.2.1/jasmine-html.js"></script>
  <script data-require="jasmine@*" data-semver="2.2.1" src="http://cdnjs.cloudflare.com/ajax/libs/jasmine/2.2.1/boot.js"></script>
  
  <script src="config.js"></script>
  <script src="https://code.angularjs.org/2.0.0-alpha.37/angular2.min.js"></script>
  <script>
    System.import('app')
      .catch(console.error.bind(console));
  </script>

</head>

<body>
  <app></app>
</body>

</html>

The above code will work properly if "numberOfTicks" is just a number, (as the plunker original example shows) but once I change it to an array and push data, it won't update.

如果“numberOfTicks”只是一个数字,则上面的代码将正常工作(如plunker原始示例所示),但是一旦我将其更改为数组并推送数据,它就不会更新。

I can't seem to understand why is that.

我似乎无法理解为什么会这样。

The following behaviour is similar to an issue I have when trying to update a graph in angular2 with new data points when using setInterval / setTimeout.

以下行为类似于我在使用 setInterval / setTimeout 时尝试使用新数据点更新 angular2 中的图形时遇到的问题。

Thanks for the help.

谢谢您的帮助。

回答by Thierry Templier

You need to update the whole reference of your array after adding an element in it:

在其中添加元素后,您需要更新数组的整个引用:

  constructor(private ref: ChangeDetectorRef) {
    setInterval(() => {
      this.numberOfTicks.push(3);
      this.numberOfTicks = this.numberOfTicks.slice();
      this.ref.markForCheck();
    }, 1000);
  }
}

Edit

编辑

The DoCheck interface could also interest you since it allows you to plug your own change detection algorithm.

DoCheck 接口也可能会让您感兴趣,因为它允许您插入自己的更改检测算法。

See this link for more details:

有关更多详细信息,请参阅此链接:

Here is a sample:

这是一个示例:

@Component({
  selector: 'custom-check',
  template: `
    <ul>
      <li *ngFor="#line of logs">{{line}}</li>
    </ul>`
})
class CustomCheckComponent implements DoCheck {
  @Input() list: any[];
  differ: any;
  logs = [];

  constructor(differs: IterableDiffers) {
    this.differ = differs.find([]).create(null);
  }

  ngDoCheck() {
    var changes = this.differ.diff(this.list);
    if (changes) {
      changes.forEachAddedItem(r => this.logs.push('added ' + r.item));
      changes.forEachRemovedItem(r => this.logs.push('removed ' + r.item))
    }
  }
}

回答by Mark Rajcok

The above code will work properly if "numberOfTicks" is just a number, but once I change it to an array and push data, it won't update. I can't seem to understand why is that.

如果“numberOfTicks”只是一个数字,上面的代码将正常工作,但是一旦我将其更改为数组并推送数据,它就不会更新。我似乎无法理解为什么会这样。

It is because a number is a JavaScript primitive type, and an array is a JavaScript reference type. When Angular change detection runs, it uses ===to determine if a template binding has changed.

这是因为数字是 JavaScript 原始类型,而数组是 JavaScript 引用类型。当 Angular 更改检测运行时,它用于===确定模板绑定是否已更改。

If {{numberOfTicks}}is a primitive type, ===compares the current and previous values. So the values 0and 1are different.

如果{{numberOfTicks}}是原始类型,则===比较当前值和先前值。所以值01是不同的。

If {{numberOfTicks}}is a reference type, ===compares the current and previous (reference) values. So if the array reference didn't change, Angular won't detect a change. In your case, using push(), the array reference isn't changing.

如果{{numberOfTicks}}是引用类型,则===比较当前和以前的(引用)值。所以如果数组引用没有改变,Angular 不会检测到变化。在您的情况下,使用push(),数组引用不会改变。

If you put the following in your template instead

如果您将以下内容放入模板中

<div *ngFor="#tick of numberOfTicks">{{tick}}</div>

then Angular would update the view because there is a binding to each array element, rather then just the array itself. So if a new item is push()ed, or an existing item is deleted or changed, all of these changes will be detected.

然后 Angular 会更新视图,因为每个数组元素都有一个绑定,而不仅仅是数组本身。因此,如果push()编辑了新项目,或者删除或更改了现有项目,所有这些更改都将被检测到。

So in your chart plunker, the following should update when the contents of the fromand toarrays change:

因此,在您的图表 plunker 中,当fromto数组的内容更改时,以下内容应更新:

<span *ngFor="#item of from">{{item}}</span>
<span *ngFor="#item of to">{{item}}</span>

Well, it will update if each item is a primitive type.

好吧,如果每个项目都是原始类型,它就会更新。