Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
236 views
in Technique[技术] by (71.8m points)

angular - How to make HTTP request at an interval?

I am quite new to angular and rxjs. I am trying to create an angular2 app that gets some data from staticly served text file(Locally on server), which I would like to retrieve and map to Datamodel using Angular2's http provider and rxjs's map at a fixed time interval(5000). To reflect any changes to the served txt file.

With rxjs 4.x I know you could use Observable.interval(5000) to do the job, but it does not seem to exist in rxjs 5. My workaround currently refresh the whole application using <meta http-equiv="refresh" content="5" > Which reloads the whole page, and thus reloads the data.

So what I would really like is some way to do this working with observables, maybe to check if any changes have happened. or just to reload the data anew.

Any help or other/better way will be very much appreciated.

What I have so far:

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

Dependencies: 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 imports:

<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>
Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As @Adam and @Ploppy mentioned, the Observable.interval() is now deprecated not the preferred way of creating such an observable. The preferred way of doing this is via the IntervalObservable or TimerObservable. [currently in Typscript 2.5.2, rxjs 5.4.3, Angular 4.0.0]

I wanted to add some usage to this answer to demonstrate what I found the best way of doing this in the Angular 2 framework.

First your service (created in angular cli via the 'ng g service MyExample" command). Assuming the service is RESTful (http get request returns a 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());
  }
}

*** see bottom updates to service for Angular 5 ***

Now your component code ('ng g component 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
  }
}

=== edit ===

Updated the component ts code to consolidate the subscriptions via a 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
  }
}

=== edit ===

my-example-service.ts (using the 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);
  }
}

Note change to use the HttpClient rather than Http (deprecated in angular5) and the get method which allows for parsing the response into our data model without having to employ the rxjs .map() operator. While the service changes for angular 5, the component code remains unchanged.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...