Angular2 освежающий вид при нажатии массива
Кажется, я не могу получить представление angular2 для обновления в функции array.push, вызванной из операции async setInterval.
код из этого angular Пример plunkr для 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="[email protected]*" 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>
Ответы
Ответ 1
Вам необходимо обновить всю ссылку вашего массива после добавления в нее элемента:
constructor(private ref: ChangeDetectorRef) {
setInterval(() => {
this.numberOfTicks.push(3);
this.numberOfTicks = this.numberOfTicks.slice();
this.ref.markForCheck();
}, 1000);
}
}
Edit
Интерфейс DoCheck также может вас заинтересовать, поскольку он позволяет вам подключить собственный алгоритм обнаружения изменений.
См. эту ссылку для получения более подробной информации:
Вот пример:
@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))
}
}
}
Ответ 2
Вышеприведенный код будет работать правильно, если "numberOfTicks" - это просто число, но как только я его сменил на массив и выталкивал данные, он не будет обновляться. Я не могу понять, почему.
Это потому, что число является примитивным типом JavaScript, а массив - ссылочным типом JavaScript. Когда Angular изменяет прогоны обнаружения, он использует ===
, чтобы определить, изменилось ли привязка шаблона.
Если {{numberOfTicks}}
является примитивным типом, ===
сравнивает текущее и предыдущее значения. Значения 0
и 1
различны.
Если {{numberOfTicks}}
является ссылочным типом, ===
сравнивает текущие и предыдущие (ссылочные) значения. Поэтому, если ссылка массива не изменилась, Angular не обнаружит изменения. В вашем случае, используя push()
, ссылка массива не изменяется.
Если вы разместите вместо этого в своем шаблоне
<div *ngFor="#tick of numberOfTicks">{{tick}}</div>
то Angular обновит представление, потому что есть привязка к каждому элементу массива, а не только к самому массиву. Поэтому, если новый элемент push()
ed, или существующий элемент удален или изменен, все эти изменения будут обнаружены.
Итак, в вашем плунжере диаграммы следующее обновление должно обновляться, когда изменяется содержимое массивов from
и to
:
<span *ngFor="#item of from">{{item}}</span>
<span *ngFor="#item of to">{{item}}</span>
Ну, он будет обновляться, если каждый элемент является примитивным типом.