Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger update of component view from service - No Provider for ChangeDetectorRef

I would like to udpate my application view, triggered by events from service.

One of my services injects the ChangeDetectorRef. Compilation works, but I am getting an error in the browser when the App is bootstrapped: No provider for ChangeDetectorRef!.

I thought I needed to add it to my AppModule, but I can't find any documentation that suggests it is in a module that I can import there. I tried adding the class itself to the import array, but that caused an error. I also got an error trying to add it to the providers array in the module. Here is a simplified version of my 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(); } 

And the app module:

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 {} 

UPDATE

I have since tried removing my use of ChangeDetectorRef, and I still have the same problem. I am guessing there is something wrong about how I updated my System JS config.

I originally created the app with angular-cli, and was trying to update Angular on my own since they had not updated that. With the final release of Angular 2.0.0 they have updated angular-cli to use the latest version of angular. So I am going to try using their upgrade procedures and hopefully that goes better.

Update 2

The webpack/angular-cli update went well. I have the app building now with Angular 2.0.0 in and angular-cli 1.0.0-beta14. I still get the same error in the browser. I tried removing the ChangeDetectorRef from the service, but I didn't really. I had it in two services. If I remove it from both services, then my app loads fine, and works well, except for where I was trying to use ChangeDetectorRef. Once I add it back in one of the files, the browser has complains about not being able to find a provider for it.

I tried importing it in my module, but it is not a module, so the transpiler complains. I tried listing it a a provider in my module, but it does not have a provide property, so the transpiler complains. similar issues if I try putting it in the declarations array.

like image 632
EricJ Avatar asked Sep 15 '16 13:09

EricJ


People also ask

What does ChangeDetectorRef detectChanges () do?

detectChanges()link Checks this view and its children. Use in combination with detach to implement local change detection checks.

What is the difference between detectChanges and markForCheck?

It offers two methods: markForCheck marks component and it's children for check in the next cycle, while detectChanges — actually fires the change detection mechanism straight away.

What are the ways to trigger change detection in angular?

We can trigger change detection manually by using detectChanges() , ApplicationRef. tick() , and markForCheck() that we mentioned earlier on AsyncPipe . detectChanges() on ChangeDetectorRef which will run change detection on this view and its children.

How does angular 2 detect changes?

There are two types of change detection: default change detection: Angular decides if the view needs to be updated by comparing all the template expression values before and after the occurrence of an event, for all components of the component tree.


1 Answers

ChangeDetectorRef is not option to use here. It is looking for changes in a given component and its children.

In your case It would be better to use 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();   } } 

I checked this solution with Observables and it works without any problems:

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;     } } 

and here is a component which uses it:

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;         });     } } 
like image 131
Maciej Treder Avatar answered Oct 15 '22 20:10

Maciej Treder