Angular2 освежающий вид на массив push

Я не могу получить представление angular2 для обновления в массиве.функция push, вызываемая из асинхронной операции setInterval.

код от этой угловой 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="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), но как только я изменю его на массив и push data, он не будет обновляться.

Я не могу понять, почему это.

следующее поведение похоже на проблему, которую я имею при попытке обновить график в angular2 с новыми точками данных при использовании setInterval / setTimeout.

Спасибо за помощь.

2 ответов


вам нужно обновить всю ссылку вашего массива после добавления в него элемента:

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

редактировать

интерфейс 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))
    }
  }
}

приведенный выше код будет работать правильно, если "numberOfTicks" - это просто число, но как только я изменю его на массив и нажму данные, он не будет обновляться. Не могу понять, почему.

это потому, что число является примитивным типом JavaScript, а массив-ссылочным типом JavaScript. Когда выполняется обнаружение угловых изменений, он использует === чтобы определить, изменилась ли привязка шаблона.

если {{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>

Ну, он будет обновляться, если каждый элемент является примитивным типом.