如何使用 Http 为 Angular 2 中的特定组件正确使用进度微调器?

How to correctly use a progress spinner for a particular component in Angular 2 using Http?

我有一个基本的 Angular 组件如下。从这个组件中,我生成了一个 TestObj 类型的对象数组,并使用相同的数组对 if kth (0 <= k <= x.length 的所有元素进行同步 post-调用) 元素处理失败,数组的剩余部分不处理。

处理-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 => {

        })
    }
}

我的服务如下所示

处理-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);
    }

}

我的模板如下

处理-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>

另外我想做的是显示一个进度微调器,当 post-调用一个类型为 TestObj 的对象时显示它,当我们从后端得到响应时隐藏它特定对象。此进度微调器必须完全禁用 UI 屏幕。

我尝试使用拦截器服务来实现相同的目的。问题在于拦截器显示整个前端进行的所有调用的进度微调器,而我想要实现的是做同样的事情,但仅针对 ProcessingComponent[= 进行的 http 调用40=]一个人。我尝试获取一个局部变量 isLoading 并在 ProcessingComponentconstructor 中将其设置为 false 并在执行 startBatchRun 时将 isLoading 设置为 true并在 startBatchRun 退出时将其设置为 false。有什么方法可以实现可观察管道的功能吗?

您应该查看 Angular Material 文档中描述的实现,在数据 table 示例下,特别是“Table retrieving data through 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);
}

这样,你只需要一个局部布尔变量,hide/show根据变量状态的微调器。

如果你想对你的请求进行去抖动(所以它不会每次都显示,即使是最后 100ms 的请求),你可以在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);
}),

...