web-dev-qa-db-fra.com

Vue rafraîchissante Angular2 sur la poussée de la baie

Je n'arrive pas à obtenir la vue angular2 à mettre à jour sur une fonction array.Push, appelée à partir d'une opération asynchrone setInterval.

le code est de ceci exemple plunkr angulaire de setInterval :

Ce que j'essaie de faire est le suivant:

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>

Le code ci-dessus fonctionnera correctement si "numberOfTicks" est juste un nombre (comme le montre l'exemple original de plunker) mais une fois que je le changerai en un tableau et des données Push, il ne sera pas mis à jour.

Je n'arrive pas à comprendre pourquoi.

Le comportement suivant est similaire à un problème que j'ai lorsque j'essaie de mettre à jour un graphique dans angular2 avec de nouveaux points de données lors de l'utilisation de setInterval/setTimeout.

Merci pour l'aide.

13
Omer Kushmaro

Vous devez mettre à jour la référence entière de votre tableau après y avoir ajouté un élément:

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

Modifier

L'interface DoCheck pourrait également vous intéresser car elle vous permet de brancher votre propre algorithme de détection de changement.

Voir ce lien pour plus de détails:

Voici un exemple:

@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))
    }
  }
}
19
Thierry Templier

Le code ci-dessus fonctionnera correctement si "numberOfTicks" n'est qu'un nombre, mais une fois que je le changerai en tableau et en données Push, il ne sera pas mis à jour. Je n'arrive pas à comprendre pourquoi.

En effet, un nombre est un type primitif JavaScript et un tableau est un type de référence JavaScript. Lorsque Angular s'exécute, il utilise === Pour déterminer si une liaison de modèle a changé.

Si {{numberOfTicks}} Est un type primitif, === Compare les valeurs actuelles et précédentes. Les valeurs 0 Et 1 Sont donc différentes.

Si {{numberOfTicks}} Est un type de référence, === Compare les valeurs actuelles et précédentes (référence). Donc, si la référence du tableau n'a pas changé, Angular ne détectera pas de changement. Dans votre cas, en utilisant Push(), la référence du tableau ne change pas.

Si vous mettez plutôt ce qui suit dans votre modèle

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

alors Angular mettrait à jour la vue car il y a une liaison à chaque élément du tableau, plutôt que juste le tableau lui-même. Donc, si un nouvel élément est Push() ed, ou un élément existant est supprimé ou modifié, toutes ces modifications seront détectées.

Ainsi, dans votre plongeur graphique, les éléments suivants doivent être mis à jour lorsque le contenu des tableaux from et to change:

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

Eh bien, il sera mis à jour si chaque élément est de type primitif.

9
Mark Rajcok