Как правильно использовать счетчик прогресса для определенного компонента в Angular 2 с помощью Http? - PullRequest
0 голосов
/ 28 февраля 2020

У меня есть базовый c Angular компонент следующим образом. Из этого компонента я генерирую массив объектов типа TestObj и использую этот же массив для синхронного пост-вызова для всех элементов при условии, что если элемент kth (0 <= k <= x.length) не будет обработан, остальная часть массива не обрабатывается. </p>

processing-component.component.ts

import { Component, OnInit } from "@angular/core";
import { FormBuilder, Form, FormGroup } from "@angular/forms";
import { Router } from "@angular/router";
import { processingService } from "./processing-component.service";
import { catchError, finalize,  map } from "rxjs/operators";
import { concat } from "rxjs/observable/concat";

import { Observable, BehaviorSubject } from "rxjs";
export class TestObj {
    processedFor:string;
    isProcessingHappened: boolean ;
    isProcessingSuccess: boolean;
    constructor(isProcessingHappened,isProcessingSuccess) {
        this.isProcessingHappened = isProcessingHappened;
        this.isProcessingSuccess = isProcessingSuccess;
    }
}

@Component({
    selector: 'processing-component',
    templateUrl: './processing-component.component.html',
    styleUrls:['./processing-component.component.scss'],
    providers: [ProcessingService]
})
export class ProcessingComponent {

    constructor(private processingService: ProcessingService) {    }    

//some array generation logic to fetch arrayToProcess

    public arrayToProcess: Array<TestObj>= [];
    public displayedColumns: string[] = ['processedFor',  'isProcessingHappened', 'isProcessingSuccess']

    public startBatchRun() {            
        const processes = this.arrayToProcess.map(details => this.processingService.runBatchExperiment(details).pipe(
          map(() => {
            this.isLoading.next(true);   
            details.isProcessingSuccess = true;
            return this.arrayToProcess;
          }),
          catchError(() => {
            this.isLoading.next(false);
            details.isProcessingSuccess = false;
            throw(false);
          }),
          finalize(() => {
            this.isLoading.next(false);
            details.isProcessingHappened = true;
          }),
        ));
        concat(...processes)
        .map(() => this.isLoading = true)
        .subscribe(res => {

        })
    }
}

Мой сервис выглядит следующим образом

processing-component.service.ts

import { Injectable, Inject } from "@angular/core";
import { Http } from "@angular/http";

@Injectable()
export class ProcessingService {

    constructor(@Inject('portfolioBaseUrl') private portfolioBaseUrl: string, 
    private http: Http) {}

    processingUrl = this.portfolioBaseUrl + '/process/'

    public runBatchExperiment(processingObj:TestObj ) {
        return this.http.post(`${this.processingUrl}`,processingObj);
    }

}

Мой шаблон выглядит следующим образом

processing-component.component. html

<button *ngIf = "arrayToProcess.length > 0" mat-raised-button  (click) = "startBatchRun()" >Start Processing</button>   

<div *ngIf = "arrayToProcess.length > 0" >
    <mat-table [dataSource] = "arrayToProcess" >

        <ng-container matColumnDef="processedFor">
            <mat-header-cell *matHeaderCellDef> ID</mat-header-cell>
            <mat-cell *matCellDef="let element"> {{element.processedFor }} </mat-cell> <!--add pipe here-->
        </ng-container>


        <ng-container matColumnDef="isProcessingHappened">
            <mat-header-cell *matHeaderCellDef> Proceesing happened </mat-header-cell>
            <mat-cell *matCellDef="let element">  
                <mat-icon *ngIf = "element.isProcessingHappened === true" >done</mat-icon>
                <mat-icon *ngIf = "element.isProcessingHappened === false" >error_outline</mat-icon>
            </mat-cell>
        </ng-container>


        <ng-container matColumnDef="isProcessingSuccess">
            <mat-header-cell *matHeaderCellDef> Batch success </mat-header-cell>
            <mat-cell *matCellDef="let element"> 
                <mat-icon *ngIf = "element.isProcessingSuccess === true" >done</mat-icon>
                <mat-icon *ngIf = "element.isProcessingSuccess === false" >error_outline</mat-icon>
            </mat-cell>
        </ng-container>

        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
    </mat-table>
</div>

Кроме того, я хочу отобразить счетчик хода выполнения, который отображается, когда пост-вызов идет для объекта типа TestObj, и скрывается, когда мы получаем ответ от серверной части для конкретного объекта. Этот индикатор выполнения должен полностью отключить экран пользовательского интерфейса.

Я пытался использовать службу перехватчика, чтобы добиться того же. Проблема в том, что перехватчик отображает счетчик хода выполнения для всех вызовов, сделанных всем внешним интерфейсом, и я пытаюсь сделать то же самое, но только для вызовов http, сделанных только ProcessingComponent, Я попытался взять локальную переменную isLoading и установить ее в false в constructor из ProcessingComponent и при выполнении startBatchRun, я установил isLoading в true и установил ее в false на выходе из startBatchRun. Есть ли способ, которым я могу достичь функциональности из наблюдаемой трубы?

1 Ответ

0 голосов
/ 28 февраля 2020

Вы должны взглянуть на реализацию, описанную в документации Angular Material, под примерами таблицы данных, в частности, на таблицу ", извлекающую данные по HTTP ".

Соответствующий фрагмент кода:

displayedColumns: string[] = ['created', 'state', 'number', 'title'];
data: GithubIssue[] = [];
isLoadingResults = true;

...

ngAfterViewInit() {

  ...

  merge(this.sort.sortChange, this.paginator.page)
    .pipe(
      startWith({}),
      switchMap(() => {
        this.isLoadingResults = true;
        return this.exampleDatabase!.getRepoIssues(this.sort.active, this.sort.direction, this.paginator.pageIndex);
      }),
      map(data => {

        ...

        this.isLoadingResults = false;

        ...

        return data.items;
      }),
      catchError(() => {

        ...

        return observableOf([]);
      })
    ).subscribe(data => this.data = data);
}

Таким образом, вам нужна только локальная логическая переменная, и вы можете скрыть / показать счетчик в соответствии с состоянием переменной.

В случае, если вы хотите иметь отклик на ваши запросы (поэтому он не будет отображаться каждый раз, даже если запросы продолжаются 100ms), вы можете добавить timer в switchMap() следующим образом:

...

switchMap(() => {          
    const result$ = this.exampleDatabase!.getRepoIssues(this.sort.active, this.sort.direction, this.paginator.pageIndex);
    timer(100).pipe(takeUntil(result$)).subscribe(t => this.isLoadingResults = true);
}),

...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...