数组推送的 Angular2 刷新视图
Angular2 refreshing view on array push
我似乎无法在 setInterval 异步操作调用的 array.push 函数上更新 angular2 视图。
代码来自angular plunkr example of setInterval:
我正在尝试做的事情如下:
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>
如果 "numberOfTicks" 只是一个数字,上面的代码将正常工作,(如 plunker 原始示例所示)但是一旦我将其更改为数组并推送数据,它就不会更新。
我似乎不明白这是为什么。
以下行为类似于我在使用 setInterval / setTimeout 时尝试使用新数据点更新 angular2 中的图形时遇到的问题。
感谢您的帮助。
您需要在添加元素后更新数组的整个引用:
constructor(private ref: ChangeDetectorRef) {
setInterval(() => {
this.numberOfTicks.push(3);
this.numberOfTicks = this.numberOfTicks.slice();
this.ref.markForCheck();
}, 1000);
}
}
编辑
您也可能对 DoCheck 接口感兴趣,因为它允许您插入自己的更改检测算法。
有关详细信息,请参阅此 link:
这是一个示例:
@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))
}
}
}
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.
因为数字是JavaScript原始类型,而数组是JavaScript引用类型。当 Angular 更改检测运行时,它使用 ===
来确定模板绑定是否已更改。
如果 {{numberOfTicks}}
是基本类型,===
比较当前值和先前值。所以值 0
和 1
是不同的。
如果 {{numberOfTicks}}
是引用类型,===
比较当前和以前的(引用)值。因此,如果数组引用未更改,Angular 将不会检测到更改。在你的例子中,使用 push()
,数组引用没有改变。
如果您将以下内容放入模板中
<div *ngFor="#tick of numberOfTicks">{{tick}}</div>
然后 Angular 将更新视图,因为每个数组元素都有一个绑定,而不仅仅是数组本身。因此,如果 push()
编辑了新项目,或者删除或更改了现有项目,所有这些更改都将被检测到。
所以在你的图表插件中,当 from
和 to
数组的内容发生变化时,以下内容应该更新:
<span *ngFor="#item of from">{{item}}</span>
<span *ngFor="#item of to">{{item}}</span>
好吧,如果每个项目都是原始类型,它会更新。
我似乎无法在 setInterval 异步操作调用的 array.push 函数上更新 angular2 视图。
代码来自angular plunkr example of setInterval:
我正在尝试做的事情如下:
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>
如果 "numberOfTicks" 只是一个数字,上面的代码将正常工作,(如 plunker 原始示例所示)但是一旦我将其更改为数组并推送数据,它就不会更新。
我似乎不明白这是为什么。
以下行为类似于我在使用 setInterval / setTimeout 时尝试使用新数据点更新 angular2 中的图形时遇到的问题。
感谢您的帮助。
您需要在添加元素后更新数组的整个引用:
constructor(private ref: ChangeDetectorRef) {
setInterval(() => {
this.numberOfTicks.push(3);
this.numberOfTicks = this.numberOfTicks.slice();
this.ref.markForCheck();
}, 1000);
}
}
编辑
您也可能对 DoCheck 接口感兴趣,因为它允许您插入自己的更改检测算法。
有关详细信息,请参阅此 link:
这是一个示例:
@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))
}
}
}
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.
因为数字是JavaScript原始类型,而数组是JavaScript引用类型。当 Angular 更改检测运行时,它使用 ===
来确定模板绑定是否已更改。
如果 {{numberOfTicks}}
是基本类型,===
比较当前值和先前值。所以值 0
和 1
是不同的。
如果 {{numberOfTicks}}
是引用类型,===
比较当前和以前的(引用)值。因此,如果数组引用未更改,Angular 将不会检测到更改。在你的例子中,使用 push()
,数组引用没有改变。
如果您将以下内容放入模板中
<div *ngFor="#tick of numberOfTicks">{{tick}}</div>
然后 Angular 将更新视图,因为每个数组元素都有一个绑定,而不仅仅是数组本身。因此,如果 push()
编辑了新项目,或者删除或更改了现有项目,所有这些更改都将被检测到。
所以在你的图表插件中,当 from
和 to
数组的内容发生变化时,以下内容应该更新:
<span *ngFor="#item of from">{{item}}</span>
<span *ngFor="#item of to">{{item}}</span>
好吧,如果每个项目都是原始类型,它会更新。