web-dev-qa-db-fra.com

Angular 2 http à un intervalle

Je suis assez nouveau pour angular et rxjs. J'essaie de créer une application angular2 qui récupère des données d'un fichier texte servi de manière statique (localement sur le serveur), que je souhaite récupérer et mapper vers Datamodel à l'aide du fournisseur http d'Angular2 et de la carte de rxjs à une heure fixe interval(5000). Pour refléter toutes les modifications apportées au fichier txt servi.

Avec rxjs 4.x, je sais que vous pouvez utiliser Observable.interval(5000) pour effectuer le travail, mais cela ne semble pas exister dans rxjs 5. Ma solution de contournement actualise actuellement l’application entière à l’aide de <meta http-equiv="refresh" content="5" > qui recharge la page entière. et recharge ainsi les données.

Donc, ce que j'aimerais vraiment, c'est une façon de faire cela en utilisant des observables, peut-être pour vérifier si des changements sont survenus. ou simplement pour recharger les données à nouveau.

Toute aide ou autre/meilleure façon sera très appréciée.

Ce que j'ai jusqu'ici:

@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")
        );
    }
}

Dépendances: 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 importations:

<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>
58
Tony Krøger

Comme @Adam et @Ploppy l'ont mentionné, Observable.interval () est maintenant obsolète pas le moyen privilégié de créer un tel observable. La méthode préférée pour ce faire consiste à utiliser IntervalObservable ou TimerObservable. [actuellement dans Typscript 2.5.2, rxjs 5.4.3, Angular 4.0.0]

Je voulais ajouter un peu d’utilisation à cette réponse pour démontrer ce que j’ai trouvé le meilleur moyen de le faire dans le cadre Angular 2.

Tout d’abord votre service (créé dans angular cli via la commande 'ng g service MyExample "). En supposant que le service soit RESTful (la requête http get renvoie un 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());
  }
}

*** voir les dernières mises à jour de service pour Angular 5 ***

Maintenant, votre code de composant ('ng g composant MyExample'):

mon-exemple.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
  }
}

=== modifier ===

Mise à jour du code du composant pour consolider les abonnements via un 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
  }
}

=== modifier ===

my-example-service.ts (utilisant le HttpClient à 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);
  }
}

Remarque: changez pour utiliser HttpClient plutôt que Http (obsolète dans angular5) et la méthode get qui permet d'analyser la réponse dans notre modèle de données sans avoir à utiliser l'opérateur rxjs .map (). Pendant que le service change pour angular 5, le code du composant reste inchangé.

83
ZackDeRose

Vous pouvez utiliser la méthode interval de Observable dans Angular2.

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

Voici le code correspondant décrivant ceci: https://plnkr.co/edit/pVMEbbGSzMwSBS4XEXJI?p=preview .

Sur cette base, vous pouvez connecter votre requête HTTP:

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

Je pense que cette réponse n’est plus valide en raison des modifications récentes de rxjs/observable. Vous devez maintenant utiliser 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

Pour TypeScript (1.8.10 au moment de la réponse)/angular2 (rc1 au moment de la réponse) avec [email protected] (beta.6 au moment de la réponse), vous devez utiliser le paramètre IntervalObservable qui étend le paramètre Observable classe

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

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

cela peut être facilement fait via switchMap

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

Disaclaimer: ceci était à l'origine une édition pour une autre réponse, mais contient trop de modifications.

Ceci peut être facilement fait via switchMap:

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

Ou en RxJS 6 syntaxe:

import { timer } from 'rxjs';
import { switchMap } from 'rxjs/operators';

timer(0, 5000) // repeats every 5 seconds
  .pipe(switchMap(() => this.http.get(...).pipe(...))
  .subscribe(...);

Vous pouvez même utiliser un interval au lieu d'un timer:

import { interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';

interval(5000) // repeats every 5 seconds
  .pipe(switchMap(() => this.http.get(...).pipe(...))
  .subscribe(...);
0
Machado