web-dev-qa-db-fra.com

mise à jour des modifications variables dans les composants depuis un service avec angular2

Mon application a un NameService qui contient le nom.

Deux composants enfants, App, Navbar et TheContent, font référence à ce service. Chaque fois que le nom change dans le service, je souhaite qu'il soit mis à jour dans les deux autres composants. Comment puis-je faire ceci?

import {Component, Injectable} from 'angular2/core'

// Name Service

@Injectable()
class NameService {
  name: any;
  constructor() {
    this.name = "Jack";
  }
  change(){
    this.name = "Jane";
  }
}

// The navbar
@Component({
  selector: 'navbar',
  template: '<div>This is the navbar, user name is {{name}}.</div>'
})
export class Navbar {
  name: any;
  constructor(nameService: NameService) {
    this.name = nameService.name;
  }
}

// The content area
@Component({
  selector: 'thecontent',
  template: '<div>This is the content area. Hello user {{name}}. <button (click)=changeMyName()>Change the name</button></div>'
})
export class TheContent {

  name: any;

  constructor(public nameService: NameService) {
    this.name = nameService.name;
  }
  changeMyName() {
       this.nameService.change();
     console.log(this.nameService.name);
  }
}


@Component({
  selector: 'app',
  providers: [NameService],
  directives: [TheContent, Navbar],
  template: '<navbar></navbar><thecontent></thecontent>'
})
export class App {
  constructor(public nameService: NameService) {
  }
}
70
B Hull

Fournissez un événement dans le service et abonnez-vous à celui-ci dans les composants:

@Injectable()
class NameService {
  name: any;
  // EventEmitter should not be used this way - only for `@Output()`s
  //nameChange: EventEmitter<string> = new EventEmitter<string>();
  nameChange: Subject<string> = new Subject<string>();
  constructor() {
    this.name = "Jack";
  }
  change(){
    this.name = 'Jane';
    this.nameChange.next(this.name);
  }
}
export class SomeComponent { 
  constructor(private nameService: NameService) {
    this.name = nameService.name;
    this._subscription = nameService.nameChange.subscribe((value) => { 
      this.name = value; 
    });
  }

  ngOnDestroy() {
   //prevent memory leak when component destroyed
    this._subscription.unsubscribe();
  }
}

Voir également
angular.io - INTERACTION COMPOSANTE - Le parent et les enfants communiquent via un service

90
Günter Zöchbauer

Comme name dans NameService est un type primitif, vous obtiendrez une instance différente dans le service et vos composants. Lorsque vous modifiez name dans NameService, les propriétés du composant ont toujours la valeur initiale et la liaison ne fonctionne pas comme prévu.

Vous devez appliquer ici la "règle du point" angular1 et vous lier à un type de référence. Modifiez NameService pour stocker un objet contenant le nom.

export interface Info {
   name:string;
}

@Injectable()
class NameService {
  info: Info = { name : "Jack" };
  change(){
    this.info.name = "Jane";
  }
}

Vous pouvez vous lier à cet objet et obtenir automatiquement les mises à jour de la propriété name.

// The navbar
@Component({
  selector: 'navbar',
  template: '<div>This is the navbar, user name is {{info.name}}.</div>'
})
export class Navbar {
  info: Info;
  constructor(nameService: NameService) {
    this.info = nameService.info;
  }
}
21
hansmaad

Je pense que la solution fournie par Günter est la meilleure.

Cela dit, vous devez savoir que les services Angular2 sont des singleton qui ont lieu dans un arbre d’injecteurs. Cela signifie que:

  • si vous définissez votre service au niveau de l'application (dans le deuxième paramètre de la méthode bootstrap], l'instance peut être partagée par tous les éléments (composants et service).
  • si vous définissez votre service au niveau du composant (dans l'attribut providers), l'instance sera spécifique au composant et à ses sous-composants.

Pour plus de détails sur cet aspect, vous pouvez consulter le document "Injection de dépendance hiérarchique": https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html =

J'espère que ça vous aide, Thierry

12
Thierry Templier