web-dev-qa-db-fra.com

Mise à jour du déclencheur de la vue du composant à partir du service - Aucun fournisseur pour ChangeDetectorRef

Je souhaite modifier ma vue d'application, déclenchée par des événements du service.

L'un de mes services injecte ChangeDetectorRef. La compilation fonctionne, mais je reçois une erreur dans le navigateur lorsque l'application est démarrée: No provider for ChangeDetectorRef!.

Je pensais que je devais l'ajouter à mon AppModule, mais je ne trouve aucune documentation suggérant qu'il se trouve dans un module que je peux importer ici. J'ai essayé d'ajouter la classe elle-même au tableau d'importation, mais cela a provoqué une erreur. J'ai également eu une erreur en essayant de l'ajouter au tableau de fournisseurs dans le module. Voici une version simplifiée de mon service:

import {Injectable, ChangeDetectorRef } from '@angular/core';

@Injectable()
export class MyService {
  private count: number = 0;
  constructor(private ref: ChangeDetectorRef){}

  increment() {
    this.count++;
    this.ref.detectChanges();
}

Et le module d'application:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

import { MyService } from './my.service';

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ AppComponent ],
  providers: [ MyService ],
  booststrap: [ AppComponent ]
})
export AppModule {}

MISE À JOUR

J'ai depuis essayé de supprimer mon utilisation de ChangeDetectorRef et j'ai toujours le même problème. Je devine qu'il y a quelque chose qui cloche dans la façon dont j'ai mis à jour ma configuration System JS.

À l'origine, j'avais créé l'application avec angular-cli, et j'essayais de mettre à jour moi-même Angular car ils ne l'avaient pas mise à jour. Avec la version finale de Angular 2.0.0, ils ont mis à jour angular-cli pour utiliser la dernière version d’angular. Je vais donc essayer d'utiliser leurs procédures de mise à niveau et j'espère que cela ira mieux.

Mise à jour 2

La mise à jour de webpack/angular-cli s'est bien déroulée. J'ai maintenant la construction de l'application avec Angular 2.0.0 in et angular-cli 1.0.0-beta14. J'ai toujours la même erreur dans le navigateur. J'ai essayé de supprimer le ChangeDetectorRef du service, mais je ne l'ai pas vraiment fait. Je l'ai eu dans deux services. Si je le supprime des deux services, mon application se charge correctement et fonctionne bien, sauf dans le cas où j'essayais d'utiliser ChangeDetectorRef . Une fois que je l'ai rajouté dans l'un des fichiers, le navigateur s'est plaint de ne pas pouvoir trouver un fournisseur.

J'ai essayé de l'importer dans mon module , mais ce n'est pas un module , se plaint le transpiler. J'ai essayé de le lister en tant que fournisseur dans mon module, mais il n'a pas de propriété de fourniture, le transpiler se plaint. problèmes similaires si j'essaie de le mettre dans le tableau declarations .

35
EricJ

ChangeDetectorRef n'est pas une option à utiliser ici. Elle recherche des changements dans un composant donné et ses enfants.

Dans votre cas, il serait préférable d’utiliser ApplicationRef:

import {Injectable, ApplicationRef } from '@angular/core';

@Injectable()
export class MyService {
  private count: number = 0;
  constructor(private ref: ApplicationRef) {}

  increment() {
    this.count++;
    this.ref.tick();
  }
}

J'ai vérifié cette solution avec Observables et cela fonctionne sans aucun problème:

import { ApplicationRef, Injectable } from '@angular/core';
import { Observable, ReplaySubject } from "rxjs/Rx";
import * as childProcess from 'child_process';

@Injectable()
export class Reader {

    private output: ReplaySubject<string> = new ReplaySubject<string>(0);

    constructor(private ref: ApplicationRef) {
        var readerProcess = childProcess.spawn('some-process');
        readerProcess.stdout.on('data', (data) => {
            this.output.next(data.toString());
            this.ref.tick();
        });
    }

    public getOutput():Observable<string> {
        return this.output;
    }
}

et voici un composant qui l'utilise:

import {Component} from '@angular/core';
import { ReplaySubject, Observable } from "rxjs/Rx";

import { Reader } from './reader/reader.service';

@Component({
    selector: 'app',
    template: `
    output:
    <div>{{output}}</div>
    `
})
export class App {

    public output: string;

    constructor(private reader: Reader) {}

    ngOnInit () {
        this.reader.getOutput().subscribe((val : string) => {
            this.output = val;
        });
    }
}
34
Maciej Treder

Une autre option si vous souhaitez déclencher la modification à partir du service mais permettre aux composants de contrôler si, quand et comment ils répondent consiste à configurer des abonnements.

A votre service, ajoutez un EventEmitter:

changeDetectionEmitter: EventEmitter<void> = new EventEmitter<void>();

Lorsque quelque chose se produit dans le service pouvant nécessiter le déclenchement d'un cycle de détection de changement, émettez simplement:

this.changeDetectionEmitter.emit();

Désormais, dans tous les composants qui utilisent ce service, s'ils ont besoin d'écouter les déclencheurs de changement possibles, ils peuvent s'abonner et réagir de manière appropriée:

this.myService.changeDetectionEmitter.subscribe(
    () => {
      this.cdRef.detectChanges();
    },
    (err) => {
      // handle errors...
    }
  );

J'aime un peu cette approche car elle laisse le contrôle de la détection des modifications aux composants auxquels elle appartient, mais me permet de centraliser la logique dans le service. Le service n'a pas besoin de savoir quoi que ce soit à propos de l'interface utilisateur, il s'agit simplement d'avertir quiconque écoute que quelque chose a changé.

6
TimTheEnchanter

dans les dernières versions fait partie du noyau maintenant, alors faites simplement une référence au noyau mais utilisez la variable nécessaire et devrait faire l'affaire

import { TestBed } from '@angular/core/testing';
import { ChangeDetectorRef } from '@angular/core';
import { MyService } from './my.service';

describe('MyService', () => {
    beforeEach(() => TestBed.configureTestingModule({
        providers: [ChangeDetectorRef] // <--- LOOK AT ME I'M A PROVIDER!
    }));

    it('should be created', () => {
        const service: MyService = TestBed.get(MyService);
        expect(service).toBeTruthy();
    });
});

L'espoir aide

0
Matias Nombarasco

Je sais que je suis trop en retard pour cela, mais j’ai simplement essayé de passer le ChangeDetectorRef au service via la fonction appelée.

//myservice
import { Injectable, ChangeDetectorRef } from '@angular/core';

@Injectable()
export class MyService {
  constructor(){}

  increment(ref: ChangeDetectorRef, output: number) {
    output++;
    ref.detectChanges();
}

La composante

import {Component} from '@angular/core';
import { MyService } from './myservice.service';

@Component({
    selector: 'app',
    template: `
    output:
    <div>{{output}}</div>
    `
})
export class App {

    public output: number;

    constructor(public ref: ChangeDetectorRef, private myService: MyService) {}

    ngOnInit () {
       this.myService.increment(this.ref,output)
    }
}
0
Ian Samz