我正在尝试在具有分页器的席子表上创建搜索,当组件加载功能时按预期进行,并且当我单击下一页并在开发人员工具中查看网络时,我看到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>
答案 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;
})
}