web-dev-qa-db-ja.com

一定間隔のAngular 2 http

私はangularとrxjsを初めて使用します。私は静的に提供されたテキストファイル(サーバー上でローカルに)からいくつかのデータを取得するangular2アプリを作成しようとしています。これをAngular2のhttpプロバイダーとrxjsのマップを固定時間で取得してDatamodelにマップしたいinterval(5000)。提供されたtxtファイルへの変更を反映するため。

Rxjs 4.xでは、Observable.interval(5000)を使用してジョブを実行できますが、rxjs 5には存在しないようです。私の回避策は、現在、<meta http-equiv="refresh" content="5" >を使用してアプリケーション全体を更新します。

したがって、私が本当に望んでいるのは、オブザーバブルを使用してこれを行う方法であり、おそらく変更が発生したかどうかを確認することです。または単にデータをリロードするだけです。

ヘルプまたは他の/より良い方法は非常に高く評価されます。

私がこれまでに持っているもの:

@Injectable()
export class DataService {

    constructor(private http:Http){}

    getData(url) {
        return this.http.get(url)
            .map(res => {
                return res.text();
            })
            .map(res => {
                return res.split("\n");
            })
            .map(res => {
                var dataModels: DataModel[] = [];
                res.forEach(str => {
                    var s = str.split(",");
                    if(s[0] !== "") {
                        dataModels.Push(new DataModel(s[0], parseInt(s[1]), parseInt(s[2])));
                    }
                });
                return dataModels;
            })
    }
}

@Component({
selector: 'my-app',
template: `Some html to display the data`,
providers: [DataService],
export class AppComponent {

data:DataModel[];

constructor(dataService:DataService) {}

ngOnInit() {
    this.dataService.getData('url').subscribe(
        res => {
            this.data= res;

        },
        err => console.log(err),
        () => console.log("Data received")
        );
    }
}

依存関係:package.json

"dependencies": {
  "angular2": "^2.0.0-beta.3",
  "bootstrap": "^4.0.0-alpha.2",
  "es6-promise": "^3.0.2",
  "es6-shim": "^0.33.13",
  "jquery": "^2.2.0",
  "reflect-metadata": "^0.1.2",
  "rxjs": "^5.0.0-beta.0",
  "systemjs": "^0.19.20",
  "zone.js": "^0.5.11"
},
"devDependencies": {
  "TypeScript": "^1.7.5"
}

index.htmlインポート:

<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>

<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
57
Tony Krøger

@Adamと@Ploppyが述べたように、Observable.interval()は現在 非推奨 そのようなオブザーバブルを作成するための好ましい方法ではありません。これを行うための好ましい方法は、IntervalObservableまたはTimerObservableを使用することです。 [現在Typscript 2.5.2、rxjs 5.4.3、Angular 4.0.0で]

Angular 2フレームワークでこれを行う最良の方法を見つけたことを示すために、この回答に使用方法を追加したかったのです。

まず、サービス(「ng g service MyExample」コマンドを使用してangular cliで作成されます)。サービスがRESTfulであると仮定します(http getリクエストはjsonを返します)。

my-example.service.ts

import { Injectable } from '@angular/core';
import { Http, Response} from "@angular/http";
import { MyDataModel } from "./my-data-model";
import { Observable } from "rxjs";
import 'rxjs/Rx';

@Injectable()
export class MyExampleService {
  private url = 'http://localhost:3000'; // full uri of the service to consume here

  constructor(private http: Http) { }

  get(): Observable<MyDataModel>{
    return this.http
      .get(this.url)
      .map((res: Response) => res.json());
  }
}

*** Angular 5のサービスの下部アップデートを参照してください***

コンポーネントコード(「ng gコンポーネントMyExample」):

my-example.component.ts:

import { Component, OnDestroy, OnInit } from '@angular/core';
import { MyDataModel } from "../my-data-model";
import { MyExampleService } from "../my-example.service";
import { Observable } from "rxjs";
import { IntervalObservable } from "rxjs/observable/IntervalObservable";
import 'rxjs/add/operator/takeWhile';

@Component({
  selector: 'app-my-example',
  templateUrl: './my-example.component.html',
  styleUrls: ['./my-example.component.css']
})
export class MyExampleComponent implements OnInit, OnDestroy {
  private data: MyDataModel;
  private display: boolean; // whether to display info in the component
                            // use *ngIf="display" in your html to take
                            // advantage of this

  private alive: boolean; // used to unsubscribe from the IntervalObservable
                          // when OnDestroy is called.

  constructor(private myExampleService: MyExampleService) {
    this.display = false;
    this.alive = true;
  }

  ngOnInit() {
    // get our data immediately when the component inits
    this.myExampleService.get()
      .first() // only gets fired once
      .subscribe((data) => {
        this.data = data;
        this.display = true;
      });

    // get our data every subsequent 10 seconds
    IntervalObservable.create(10000)
      .takeWhile(() => this.alive) // only fires when component is alive
      .subscribe(() => {
        this.myExampleService.get()
          .subscribe(data => {
            this.data = data;
          });
      });
  }

  ngOnDestroy(){
    this.alive = false; // switches your IntervalObservable off
  }
}

===編集===

コンポーネントtsコードを更新して、TimerObservableを介してサブスクリプションを統合しました。

import { Component, OnDestroy, OnInit } from '@angular/core';
import { MyDataModel } from "../my-data-model";
import { MyExampleService } from "../my-example.service";
import { Observable } from "rxjs";
import { TimerObservable } from "rxjs/observable/TimerObservable";
import 'rxjs/add/operator/takeWhile';

@Component({
  selector: 'app-my-example',
  templateUrl: './my-example.component.html',
  styleUrls: ['./my-example.component.css']
})
export class MyExampleComponent implements OnInit, OnDestroy {
  private data: MyDataModel;
  private display: boolean; // whether to display info in the component
                            // use *ngIf="display" in your html to take
                            // advantage of this

  private alive: boolean; // used to unsubscribe from the TimerObservable
                          // when OnDestroy is called.
  private interval: number;

  constructor(private myExampleService: MyExampleService) {
    this.display = false;
    this.alive = true;
    this.interval = 10000;
  }

  ngOnInit() {
    TimerObservable.create(0, this.interval)
      .takeWhile(() => this.alive)
      .subscribe(() => {
        this.myExampleService.get()
          .subscribe((data) => {
            this.data = data;
            if(!this.display){
              this.display = true;
            }
          });
      });
  }

  ngOnDestroy(){
    this.alive = false; // switches your TimerObservable off
  }
}

===編集===

my-example-service.ts(HttpClient a la Angular 5を使用):

import { Injectable } from '@angular/core';
import { HttpClient} from "@angular/common/http";
import { MyDataModel } from "./my-data-model";
import { Observable } from "rxjs";
import 'rxjs/Rx';

@Injectable()
export class MyExampleService {
  private url = 'http://localhost:3000'; // full uri of the service to consume here

  constructor(private http: HttpClient) { }

  get(): Observable<MyDataModel>{
    return this.http
      .get<MyDataModel>(this.url);
  }
}

HttpではなくHttpClient(angular5で非推奨)とgetメソッドを使用して、rxjs .map()演算子を使用せずにデータモデルへの応答を解析できるようにする変更に注意してください。 angular 5のサービスが変更されても、コンポーネントコードは変更されません。

82
ZackDeRose

Angular2内でintervalObservableメソッドを使用できます。

import {Component,Input} from 'angular2/core';
import {Observable} from 'rxjs/Rx';

@Component({
  selector: 'my-app',
  template: `
    <div>
      {{message}}
    </div>
  `
})
export class AppComponent {
  constructor() {
    Observable.interval(500)
          .take(10).map((x) => x+1)
          .subscribe((x) => {
            this.message = x;
          }):
  }
}

これを説明する対応するplunkrは次のとおりです。 https://plnkr.co/edit/pVMEbbGSzMwSBS4XEXJI?p=preview

これに基づいて、HTTPリクエストをプラグインできます。

initializePolling() {
  return Observable
     .interval(60000)
     .flatMap(() => {
       return this.dataService.getData('url'));
     });
}
31

Rxjs/observableの最近の変更により、この回答はもう有効ではないと思います。IntervalObservableを使用する必要があります。

https://github.com/ReactiveX/rxjs/blob/master/src/observable/IntervalObservable.ts

import { IntervalObservable } from 'rxjs/observable/IntervalObservable';

@Component({
  ...
})
export class AppComponent {
  n: number = 0;
  constructor() {
    IntervalObservable.create(1000).subscribe(n => this.n = n);
  }
}
19
Ploppy

TypeScript(回答時1.8.10)/ angular2(回答時rc1)と[email protected](回答時beta.6)の場合、IntervalObservableクラスを拡張するObservableを使用する必要があります。

import {IntervalObservable} from 'rxjs/observable/IntervalObservable'

IntervalObservable.create(5000).take(10).map((x) => x + 1)
8
Adam

これはswitchMapを介して簡単に実行できます。

Observable.timer(0, 5000)
          .switchMap((t) =>
            this.http.get(...).pipe(
                catchError(...)
            )
          )
          .subscribe(...)
0