Angular 6分页器重复请求和响应

时间:2018-10-03 21:42:52

标签: angular angular6

我正在尝试在具有分页器的席子表上创建搜索,当组件加载功能时按预期进行,并且当我单击下一页并在开发人员工具中查看网络时,我看到1个请求和1个响应,问题出在我现在搜索某物时,它仍然发出1个请求和1个响应,但是当我搜索某物后下一页时,我看到它发出2个请求并得到2个响应,因此重复,如果我再次搜索,它发出3个请求下一页之后的请求和响应等等,等等,只有一次,我再次单击下一页,但是每次搜索仍然只有1个请求和响应。

想知道是否有人可以直接引导我解决这个问题。

这里是我的组件

    import {Component, OnInit, ViewChild} from '@angular/core';
    import {MatDialogRef,MatDialog} from '@angular/material'
    import {MatPaginator, MatSort} from '@angular/material';
    import {merge, Observable, of as observableOf} from 'rxjs';
    import {catchError, map, startWith, switchMap} from 'rxjs/operators';
    import {DataService} from '@app/providers'
    import {UserAdd} from '@app/modules/features/admininstration/pages/users/modals/user_add/user_add'
    import {UserEdit} from '@app/modules/features/admininstration/pages/users/modals/user_edit/user_edit'
    import {UserOtp} from '@app/modules/features/admininstration/pages/users/modals/user_otp/user_otp'
    import * as u from '@app/models/user'

    /**
     * @title Table retrieving data through HTTP
     */
    @Component({
      selector: 'users',
      styleUrls: ['users.scss'],
      templateUrl: 'users.html',
    })
    export class Users implements OnInit {
      displayedColumns: string[] = ['username', 'firstname', 'surname','userrole','usertype', 'created','actions'];
      data: u.UserGrid[] = []
      search: string = "";
      resultsLength = 0;
      isLoadingResults = true;
      isRateLimitReached = false;

      userAdd: MatDialogRef<UserAdd>;
      userEdit: MatDialogRef<UserEdit>;
      userOtp: MatDialogRef<UserOtp>;

      @ViewChild(MatPaginator) paginator: MatPaginator;
      @ViewChild(MatSort) sort: MatSort;

      constructor(private ds:DataService,private dialog:MatDialog) {}

      ngOnInit() {
        // If the user changes the sort order, reset back to the first page.
        this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
        this.sort.direction = 'asc';
        this.sort.active = 'firstname';
        this.loadGridData();
      }

      loadGridData(){

        merge(this.sort.sortChange, this.paginator.page)
          .pipe(
            startWith({}),
            switchMap(() => {
              this.isLoadingResults = true;
              return this.ds!.getUsers(this.search,this.sort.active+'_'+this.sort.direction,10,this.paginator.pageIndex);
            }),
            map(data => {
              // Flip flag to show that loading has finished.
              this.isLoadingResults = false;
              this.isRateLimitReached = false;
              this.resultsLength = data.count;
              return data.users;
            }),
            catchError(() => {
              this.isLoadingResults = false;
              this.isRateLimitReached = true;
              return observableOf([]);
            })
          ).subscribe(data => this.data = data); 
      }

      userSearch(){
        this.paginator.pageIndex = 0;
        this.loadGridData();
      }

      openUserAdd(){
        this.userAdd = this.dialog.open(UserAdd,{
          disableClose: false,
          width: '550px',
          height: '50%',
        })
      }

      openUserEdit(id:string){
        this.userEdit = this.dialog.open(UserEdit,{
          disableClose: false,
          width: '550px',
          height: '50%',
        })
        this.userEdit.componentInstance.id = id;
      }

      openUserOtp(){
        this.userOtp = this.dialog.open(UserOtp,{
          disableClose: false,
          width: '500px',
          height: '150px'
        })
      }

      deleteUser(id:string){
        this.ds.deleteUser(id).subscribe(()=>{
          this.loadGridData();
        });

      }
    }

这是我的模板。

    <mat-toolbar color="accent" class="mini-toolbar" fxLayout="row" fxLayoutAlign="space-between center">
        <span>Users</span>

        <div fxLayout="row">
            <mat-form-field class="full-width" fxLayoutAlign="center center">
                <input placeholder="What are you looking for?" matInput [(ngModel)]="search" (keyup.enter)="userSearch()">
            </mat-form-field>
            <div fxFlex="10px"></div>
            <div class="custom_button" style="margin-top: 13px; width: 100px" fxLayoutAlign="center center" (keyup.enter)="userSearch()"
                (click)="userSearch()">
                SEARCH
            </div>
            <div fxFlex="10px"></div>
            <div class="custom_button" style="margin-top: 13px;width: 150px" fxLayoutAlign="center center" (click)="openUserAdd()">
                CREATE USER
            </div>
        </div>
    </mat-toolbar>

    <div class="example-loading-shade" *ngIf="isLoadingResults || isRateLimitReached">
        <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
        <div class="example-rate-limit-reached" *ngIf="isRateLimitReached">
            Error retrieving data.
        </div>
    </div>

    <div fxLayout="row" class="sitegroup-container" fxLayoutAlign="start stretch">
        <div fxFlex="100%" class="data_container">


            <table mat-table [dataSource]="data" class="example-table" matSort matSortActive="firstname" matSortDisableClear matSortDirection="asc">
                <!-- Username Column -->
                <ng-container matColumnDef="username">
                    <th mat-header-cell *matHeaderCellDef>Username</th>
                    <td mat-cell *matCellDef="let row">{{row.username}}</td>
                </ng-container>

                <!-- Firstname Column -->
                <ng-container matColumnDef="firstname">
                    <th mat-header-cell *matHeaderCellDef mat-sort-header disableClear>Firstname</th>
                    <td mat-cell *matCellDef="let row">{{row.firstname}}</td>
                </ng-container>

                <!-- Surname Column -->
                <ng-container matColumnDef="surname">
                    <th mat-header-cell *matHeaderCellDef mat-sort-header disableClear>Surname</th>
                    <td mat-cell *matCellDef="let row">{{row.surname}}</td>
                </ng-container>

                <!-- UserROle Column -->
                <ng-container matColumnDef="userrole">
                    <th mat-header-cell *matHeaderCellDef mat-sort-header disableClear>User Role</th>
                    <td mat-cell *matCellDef="let row">{{row.userRole}}</td>
                </ng-container>

                <!-- UserType Column -->
                <ng-container matColumnDef="usertype">
                    <th mat-header-cell *matHeaderCellDef mat-sort-header disableClear>User Type</th>
                    <td mat-cell *matCellDef="let row">{{row.userType}}</td>
                </ng-container>

                <!-- Created Column -->
                <ng-container matColumnDef="created">
                    <th mat-header-cell *matHeaderCellDef>
                        Created
                    </th>
                    <td mat-cell *matCellDef="let row">{{row.created | date}}</td>
                </ng-container>

                <!-- Actions Column-->
                <ng-container matColumnDef="actions">
                    <th mat-header-cell *matHeaderCellDef>

                    </th>
                    <td mat-cell *matCellDef="let row">
                        <div fxLayout="row" fxLayoutAlign="end">
                            <button matTooltip="OTP" [matTooltipPosition]="'left'" mat-icon-button (click)="openUserOtp()" color="accent">
                                <mat-icon>smartphone</mat-icon>
                            </button>
                            <button matTooltip="Edit" [matTooltipPosition]="'left'" mat-icon-button (click)="openUserEdit(row.id)" color="accent">
                                <mat-icon>create</mat-icon>
                            </button>
                            <button matTooltip="Delete" [matTooltipPosition]="'left'" mat-icon-button (click)="deleteUser(row.id)" color="accent">
                                <mat-icon>delete</mat-icon>
                            </button>
                        </div>
                    </td>
                </ng-container>

                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
                <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
            </table>
            <mat-paginator [length]="resultsLength" [pageSize]="10"></mat-paginator>
        </div>
    </div>

2 个答案:

答案 0 :(得分:0)

每次调用loadGridData()时,您都在合并时订阅可观察的构建。您正在通过代码执行几次此操作,而从未删除订阅。因此,添加或删除用户将创建一个全新的订阅,因为您将再次调用loadGridData(),从而增加了您正在进行的http调用的数量(较旧的订阅会因链上的更改而触发)。

数据加载方式存在两个基本问题,建议您重新评估。

一些建议:

  • 不要在后备代码内使用直接预订,而是将“加载”的结果放入一个可观察的属性中,然后使用“ async”将该属性绑定到模板上。

  • 将执行http请求的代码移至主题中,并在您的合并中混合显示。现在,无需调用整个负载,您只需让您的主题发出更新的值,您的用户界面就应该更新。

如果您使用异步,则Angular框架会为您进行外部可观察对象(来自主题的订阅)的订阅。

[注意-此处的注释替换为下面的示例]

这是一个幼稚的示例,希望它将显示一种避免连续添加调用的方法。

app.component.html

<div>
  <button (click)="loadData()">Refresh</button>
</div>
<div *ngIf="currentTime$ | async as currentTime">
  <p>{{currentTime.currentFileTime}}</p>
</div>

app.component.ts

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map, take } from 'rxjs/operators';
import { Subject } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  public currentTime$ = new Subject<any>();
  private httpClient: HttpClient;

  constructor(http: HttpClient) {
    this.httpClient = http;
  }

  public ngOnInit() {
    this.loadData();
  }

  public loadData() {
    const path = 'http://worldclockapi.com/api/json/est/now';

    const subscription = this.httpClient.get<any>(path).pipe(take(1), map((val) => val)).subscribe(
      (data) => {
        this.currentTime$.next(data);
      },
      (error) => {
        console.log(error);
      },
      () => {
        if (subscription && !subscription.closed) {
          subscription.unsubscribe();
        }
      });
  }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [ ],
  bootstrap: [AppComponent]
})
export class AppModule { }

因此,每次您按“刷新”时,都会生成一个http调用,但是较旧的订阅将在完成时关闭。 “ take(1)”使完成在第一个get上发生,从而使其表现出我认为您希望数据流动的方式。

答案 1 :(得分:0)

我更改了userSearch函数,并添加了refreshGrid函数以仅获取用户和resultsLength,而不是调用loadGrid函数,这样我就不会继续添加更多订阅。

userSearch(){
    this.paginator.pageIndex = 0;
    this.refreshGrid();
  }

refreshGrid(){
    this.isLoadingResults = true;
    this.ds!.getUsers(this.search,this.sort.active+'_'+this.sort.direction,10,this.paginator.pageIndex).subscribe((data)=>{
      this.resultsLength = data.count;
      this.data = data.users;
      this.isLoadingResults = false;
    })
}