简体   繁体   中英

Wait before display data with {HttpClient} - typescript - Angular

For 4 days I'm trying somethings to display data but nothing is running. My goal is to receive data from an internal server in the factory. So, some Siemens CPU sends data in CSV file, et I read that in

line.service.ts

import {Subject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';

@Injectable()
export class LineService{

  public lines: RcvData[] = [];

  constructor(private http: HttpClient) {
    this.getData();
  }

  lineSubject = new Subject<any[]>();

  getData(): void {
    const lists: string[] = [
      'assets/donnee-l1.csv',
      'assets/donnee-l2.csv',
      'assets/donnee-l3.csv',
      'assets/donnee-l4.csv',
      'assets/donnee-l5.csv',
      'assets/donnee-l6.csv'
    ];
    for (const list of lists) {
      this.http.get(list, {responseType: 'text'})
        .subscribe(data => {
          const csvToRowArray = data.split('\n');
          const lastRow = csvToRowArray[csvToRowArray.length - 2];
          const row = lastRow.split(',');
          this.lines.push(new RcvData(
            parseInt(row[0], 10),
            row[1], row[2], row[3], row[4], row[5],
            parseInt(row[6], 10),
            parseInt(row[7], 10),
            parseInt(row[8], 10),
            parseInt(row[9], 10),
            parseFloat(row[10]),
            parseFloat(row[11]),
            parseFloat(row[12]),
            parseFloat(row[13]),
            parseFloat(row[14]))
          );
          if(this.lines.length === 6){
            this.isLoading = true;
          }
          console.log(this.isLoading);
          console.log(this.lines.length);
        }, error => {
          console.log(error);
        });
    }
  }

  emitLineSubject(): void {
    this.lineSubject.next(this.lines.slice());
  }
  getLineById(id: number): RcvData{
    const line = this.lines.find(
      (lineObject) => {
        return lineObject.id === id;
      }
    );
    return line;
  }
}

class RcvData{
  id: number;
  date: string;
  utcTime: string;
  refCharge: string;
  refDecharge: string;
  quantiteEnCours: string;
  quantiteHoraireReel: number;
  quantiteHoraireTheorique: number;
  quantitePosteReel: number;
  quantitePosteTheorique: number;
  trpHeureReel: number;
  trpPosteReel: number;
  trpObjectif: number;
  consoAir: number;
  consoElec: number;


  constructor(
    id: number,
    date: string,
    utcTime: string,
    refCharge: string,
    refDecharge: string,
    quantiteEnCours: string,
    quantiteHoraireReel: number,
    quantiteHoraireTheorique: number,
    quantitePosteReel: number,
    quantitePosteTheorique: number,
    trpHeureReel: number,
    trpPosteReel: number,
    trpObjectif: number,
    consoAir: number,
    consoElec: number)
  {
    this.id = id;
    this.date = date;
    this.utcTime = utcTime;
    this.refCharge = refCharge;
    this.refDecharge = refDecharge;
    this.quantiteEnCours = quantiteEnCours;
    this.quantiteHoraireReel = quantiteHoraireReel;
    this.quantiteHoraireTheorique = quantiteHoraireTheorique;
    this.quantitePosteReel = quantitePosteReel;
    this.quantitePosteTheorique = quantitePosteTheorique;
    this.trpHeureReel = trpHeureReel;
    this.trpPosteReel = trpPosteReel;
    this.trpObjectif = trpObjectif;
    this.consoAir = consoAir;
    this.consoElec = consoElec;
  }
}

Now, in this.ts, I split CSV data to have an object of my 6 productions lines. And I send data for my html page, to display that. I read data with this components:

single.line.components.ts

import { Component, OnInit } from '@angular/core';
import { LineService } from '../services/line.service';
import { ActivatedRoute } from '@angular/router';
import {async} from 'rxjs-compat/scheduler/async';

@Component({
  selector: 'app-single-line',
  templateUrl: './single-line.component.html',
  styleUrls: ['./single-line.component.scss']
})
export class SingleLineComponent implements OnInit {

  name = 'Ligne...';
  status = 'éteint';
  date_jour = '2021-01-01';
  heure_act = '00:00:00';
  reference_charge = 'ST00S00';
  reference_decharge = 'ST11S11';
  quantite_produite = '1/1000';
  quantite_h_reel = 0;
  quantite_h_th = 0;
  quantite_p_reel = 0;
  quantite_p_th = 0;
  trp_h_reel = 0;
  trp_p_reel = 0;
  trp_objectif = 0;
  conso_air = 0;
  conso_elec = 0;

  private activatedRoute: ActivatedRoute;

  constructor(private lineService: LineService,
              private route: ActivatedRoute) {
              this.activatedRoute = route;
  }

  ngOnInit(): void {
    this.activatedRoute.params.subscribe(params => {
      const id = params.id;
      this.name = this.lineService.getLineById(+id).refCharge;
      this.status = this.lineService.getLineById(+id).date;
      this.date_jour = this.lineService.getLineById(+id).date;
      this.heure_act = this.lineService.getLineById(+id).utcTime;
      this.reference_charge = this.lineService.getLineById(+id).refCharge;
      this.reference_decharge = this.lineService.getLineById(+id).refDecharge;
      this.quantite_produite = this.lineService.getLineById(+id).quantiteEnCours;
      this.quantite_h_reel = this.lineService.getLineById(+id).quantiteHoraireReel;
      this.quantite_h_th = this.lineService.getLineById(+id).quantiteHoraireTheorique;
      this.quantite_p_reel = this.lineService.getLineById(+id).quantitePosteReel;
      this.quantite_p_th = this.lineService.getLineById(+id).quantitePosteTheorique;
      this.trp_h_reel = this.lineService.getLineById(+id).trpHeureReel;
      this.trp_p_reel = this.lineService.getLineById(+id).trpPosteReel;
      this.trp_objectif = this.lineService.getLineById(+id).trpObjectif;
      this.conso_air = this.lineService.getLineById(+id).consoAir;
      this.conso_elec= this.lineService.getLineById(+id).consoElec;
    });
  }
}

And to finish, my HTML page:

<div class="container-fluid">
  <div [ngClass]="{'list-group-item': true,
                'list-group-item-success': status === 'allumé',
                'list-group-item-danger' : status === 'éteint',
                'list-group-item-warning' : status === 'changement'
                }">
    <h1>
      <p *ngIf="status === 'allumé'"> {{ name }} | en production
        <span class="glyphicon glyphicon-ok"></span>
      </p>
      <p *ngIf="status === 'éteint'">{{ name }} |  à l'arrêt
        <span class="glyphicon glyphicon-remove"></span>
      </p>
      <p *ngIf="status === 'changement'">{{ name }} | changement en cours
        <span class="glyphicon glyphicon-refresh"></span>
      </p>
    </h1>
  <div class="row h3">

    <div class="col-sm-6 list-group-item-text text-center">
      <p> Référence en cours de chargement : {{ reference_charge }}</p>
      <p> Référence en cours de déchargement : {{ reference_decharge }}</p>
    </div>
  </div>

    <div class="row list-group-item-text text-center h4">
      <div class="col-sm-3 text-center">
        <p>Quantité de pièces totale : {{ quantite_produite }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>Pièces produites dans l'heure : {{ quantite_h_reel }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>Pièces à produire par heure : {{ quantite_h_th }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>Pièces produites sur le poste : {{ quantite_p_reel }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>Pièces à produire sur un poste : {{ quantite_p_th }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>TRP de l'heure: {{ trp_h_reel }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>TRP du poste: {{ trp_p_reel }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>TRP Objectif: {{ trp_objectif }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>Consommation d'air: {{ conso_air }}</p>
      </div>
      <div class="col-sm-3 text-center">
        <p>Consommation électrique : {{ conso_elec }}</p>
      </div>
        </div>
    <button class="btn btn-primary" routerLink="/lines">Retour</button>
  </div>
  <app-view-graph></app-view-graph>

</div>

But the problem is, when i reload my page, there is an error: TypeError: Cannot read property '...' of undefined. It's because the page is loading and after, the read data runs. If I change the page by my navbar and I return to the correct page, the data are here. I want to display the page only when the data are present.

I tried with Promise, Async, Await, SpinnerLoad but it does not work.

Any help is welcome. Thanks

I would suggest making your solution a bit more reactive.

First instead of using a for loop to iterate over all links and then push them in the lines[] i would suggest the following approach

 import {BehaviourSubject} from 'rxjs'; import {HttpClient} from '@angular/common/http'; import {Injectable} from '@angular/core'; @Injectable() export class LineService{ constructor(private http: HttpClient) { this.getData(); } lineSubject = new BehaviourSubject<RcvData[]>([]); getData(): void { const lists: string[] = [ 'assets/donnee-l1.csv', 'assets/donnee-l2.csv', 'assets/donnee-l3.csv', 'assets/donnee-l4.csv', 'assets/donnee-l5.csv', 'assets/donnee-l6.csv' ]; combineLatest(lists.map(list => this.http.get(list, {responseType: 'text'}))).subscribe(listResults => { const parsedListResults = listResults.map(data => { const csvToRowArray = data.split('\n'); const lastRow = csvToRowArray[csvToRowArray.length - 2]; const row = lastRow.split(','); return new RcvData( parseInt(row[0], 10), row[1], row[2], row[3], row[4], row[5], parseInt(row[6], 10), parseInt(row[7], 10), parseInt(row[8], 10), parseInt(row[9], 10), parseFloat(row[10]), parseFloat(row[11]), parseFloat(row[12]), parseFloat(row[13]), parseFloat(row[14])) }) this.lineSubject.next(parsedListResults) }) } } class RcvData{ id: number; date: string; utcTime: string; refCharge: string; refDecharge: string; quantiteEnCours: string; quantiteHoraireReel: number; quantiteHoraireTheorique: number; quantitePosteReel: number; quantitePosteTheorique: number; trpHeureReel: number; trpPosteReel: number; trpObjectif: number; consoAir: number; consoElec: number; constructor( id: number, date: string, utcTime: string, refCharge: string, refDecharge: string, quantiteEnCours: string, quantiteHoraireReel: number, quantiteHoraireTheorique: number, quantitePosteReel: number, quantitePosteTheorique: number, trpHeureReel: number, trpPosteReel: number, trpObjectif: number, consoAir: number, consoElec: number) { this.id = id; this.date = date; this.utcTime = utcTime; this.refCharge = refCharge; this.refDecharge = refDecharge; this.quantiteEnCours = quantiteEnCours; this.quantiteHoraireReel = quantiteHoraireReel; this.quantiteHoraireTheorique = quantiteHoraireTheorique; this.quantitePosteReel = quantitePosteReel; this.quantitePosteTheorique = quantitePosteTheorique; this.trpHeureReel = trpHeureReel; this.trpPosteReel = trpPosteReel; this.trpObjectif = trpObjectif; this.consoAir = consoAir; this.consoElec = consoElec; } }

The main change here is that now instead of having a static lines ref we have a "live" ref in the form of BehaviourSubject , for which we can subscribe, and be notified whenever there are any changes.

 import { Component, OnInit } from '@angular/core'; import { LineService } from '../services/line.service'; import { ActivatedRoute } from '@angular/router'; import {async} from 'rxjs-compat/scheduler/async'; @Component({ selector: 'app-single-line', templateUrl: './single-line.component.html', styleUrls: ['./single-line.component.scss'] }) export class SingleLineComponent implements OnInit { name = 'Ligne...'; status = 'éteint'; date_jour = '2021-01-01'; heure_act = '00:00:00'; reference_charge = 'ST00S00'; reference_decharge = 'ST11S11'; quantite_produite = '1/1000'; quantite_h_reel = 0; quantite_h_th = 0; quantite_p_reel = 0; quantite_p_th = 0; trp_h_reel = 0; trp_p_reel = 0; trp_objectif = 0; conso_air = 0; conso_elec = 0; focusedData$ = combineLatest( this.lineService.lineSubject.pipe(filter(x => x.length > 0)), this.route.params.pipe(filter(x=>.,x.id). map(x => x,id)) ):pipe( map(([csvs, id]) => csvs[id]) ) constructor(private lineService: LineService, private route: ActivatedRoute) { } }

Here the interesting part is the focusData$ we are combing the values stored in the behavior subject that we created in the lineService and the current id stored in the URL. We are filtering all non-valid values and after that, we map the id to the appropriate csv.

From this point on inside your template, you can do something like the following

 <div *ngIf="focusedData$ | async"> <div> {{(focusedData$ | async).refCharge }} </div> <div> {{(focusedData$ | async).date }} </div> <div> {{(focusedData$ | async).utcTime }} </div> </div>

This pseudo code will most likely help you in finding the fix for your issue, but anyway, if I was in your shoes I would think about a solution where I call only one csv at a time and when needed, also probably it's not the wisest thing to invoke http calls inside the constructor of your service.

Thanks, thanks, thanks, It works. thanks a lot.

That wasn't a "pseudo" code ^^, I change only 1 thing.

this.route.params.pipe(filter(x=> !!x.id), map(x => x.id))

by

this.route.params.pipe(filter(x=> !!x.id), map(x => x.id -1))

To have the correct data in the correct page. And, that's all.

Thanks for your answer, Have a nice day

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM