web-dev-qa-db-ja.com

サービスからのコンポーネントビューの更新のトリガー-ChangeDetectorRefのプロバイダーなし

サービスからのイベントによってトリガーされるアプリケーションビューを更新します。

私のサービスの1つがChangeDetectorRefを注入します。コンパイルは機能しますが、アプリのブートストラップ時にブラウザーでエラーが発生します:No provider for ChangeDetectorRef!

AppModuleに追加する必要があると思いましたが、そこにインポートできるモジュール内にあることを示唆するドキュメントが見つかりません。クラス自体をインポート配列に追加しようとしましたが、エラーが発生しました。また、モジュール内のプロバイダー配列に追加しようとしてエラーが発生しました。これが私のサービスの簡略版です:

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

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

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

そしてappモジュール:

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 [〜#〜]

それ以来、ChangeDetectorRefの使用を削除しようとしましたが、まだ同じ問題があります。 System JS configの更新方法に何か問題があると思います。

私はもともとangle-cliでアプリを作成しましたが、Angular=は自分で更新しようとしていました。最終リリースではAngular 2.0.0彼らは、angular-cliを更新して、angularの最新バージョンを使用しているので、アップグレード手順を使用してみますが、うまくいけばうまくいきます。

更新2

Webpack/angular-cliの更新はうまくいきました。 Angular 2.0.0 inとangle-cli 1.0.0-beta14でアプリを構築しています。ブラウザで同じエラーが表示されます。サービスからのChangeDetectorRefが、実際にはそうではありませんでした。2つのサービスに含まれていました。 ChangeDetectorRefを使用しようとしていた場所を除きます。ファイルの1つにそれを追加し直すと、ブラウザは、それのプロバイダー。

私はmoduleでインポートしようとしましたが、moduleではありません、したがって、トランスパイラーは文句を言います。私は自分のモジュールにproviderをリストしようとしましたが、provideプロパティがないため、トランスパイラーは文句を言います。 declarations配列に入れようとすると、同様の問題が発生します。

35
EricJ

ChangeDetectorRefは、ここで使用するオプションではありません。特定のコンポーネントとその子の変更を探しています。

あなたの場合は、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();
  }
}

私はObservablesでこのソリューションをチェックしましたが、問題なく動作します:

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

そして、これを使用するコンポーネントは次のとおりです。

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

サービスから変更をトリガーするが、コンポーネントが応答するかどうか、タイミング、および方法を制御できるようにする場合の別のオプションは、サブスクリプションを設定することです。

サービスにEventEmitterを追加します。

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

変更検出サイクルをトリガーする必要がある可能性のある何かがサービスで発生した場合、単純に以下を発行します。

this.changeDetectionEmitter.emit();

現在、このサービスを使用するコンポーネントでは、可能な変更トリガーをリッスンする必要がある場合、サブスクライブして適切に対応できます。

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

私はこのアプローチが好きです。なぜなら、それが属するコンポーネントで変更検出の制御を残しますが、サービスのロジックを集中化できるからです。サービスはUIについて何も知る必要はありません。何かが変更されたことを聞いている人に通知するだけです。

6
TimTheEnchanter

現在、最新バージョンではコアの一部であるため、コアへの参照を作成しますが、必要な変数を使用してトリックを行う必要があります

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

希望は助けます

0

私はこれには長い間遅れていることを知っていますが、呼び出される関数を介してChangeDetectorRefをサービスに渡すだけでした。

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

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

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

コンポーネント

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