Angular Material表在输入初始为空白时过滤掉所有结果,在输入input Only后将工作



所以我的表工作得很好,除了它不显示任何数据,直到单击一行或使用过滤器。我不确定这里发生了什么,不确定我做错了什么。

我只是想让所有的数据加载到表中。

HTML:

<div fxLayoutAlign="center center">
<button mat-mini-fab color="accent" style="margin-right: 20px">
<mat-icon class="add-course-btn" (click)="stalkUser()">person_add_alt_1</mat-icon>
</button>
<mat-form-field fxFlex="40%">
<input matInput (keyup)="doFilter($event)" placeholder="Ex. Username" #input>
</mat-form-field>
</div>

<ng-container *ngIf="usersUserStalking.length > 0 && isLoading == false">
<mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="userName">
<mat-header-cell *matHeaderCellDef mat-sort-header id="nameField">Name</mat-header-cell>
<mat-cell *matCellDef="let element"><span style="cursor:pointer" (click)="navigateProfile(element.tag)"><img mat-card-avatar src="{{element.profileImage }}" class="friends-avatar-photo"> {{ element.name}}</span></mat-cell>
</ng-container>

<ng-container matColumnDef="userTag">
<mat-header-cell *matHeaderCellDef mat-sort-header fxHide.xs>Tag</mat-header-cell>
<mat-cell *matCellDef="let element" fxHide.xs>{{element.tag }}</mat-cell>
</ng-container>

<ng-container matColumnDef="userRank">
<mat-header-cell *matHeaderCellDef mat-sort-header fxHide.xs>Rank</mat-header-cell>
<mat-cell *matCellDef="let element" fxHide.xs>{{element.rank }}</mat-cell>
</ng-container>

<ng-container matColumnDef="factionName" >
<mat-header-cell *matHeaderCellDef mat-sort-header fxHide.xs>Faction</mat-header-cell>
<mat-cell *matCellDef="let element" fxHide.xs><span style="cursor:pointer" (click)="navigateProfile(element.tag)">{{element.faction }}</span></mat-cell>
</ng-container>
<ng-container matColumnDef="stalking" >
<mat-header-cell *matHeaderCellDef>Stalking</mat-header-cell>
<mat-cell *matCellDef="let element"><button mat-stroked-button class="hover-class" color="primary"><span>Stalking</span></button></mat-cell>
</ng-container>

<!-- Row shown when there is no matching data. -->
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>
</tr>

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

<mat-paginator #paginator 
[pageSizeOptions]="[5, 10, 25, 100]">
</mat-paginator>
</ng-container>
<!-- Show if user is stalking no one -->
<ng-container *ngIf="usersUserStalking.length <= 0 && isLoading == false">
<div fxLayoutAlign="center center">
<h1>You are Stalking no one, use the yellow button above to stalk whoever you want!</h1>
</div>
</ng-container>
<ng-container *ngIf="isLoading">
<div class="spinner-container" fxLayoutAlign="center center">
<mat-spinner></mat-spinner>
</div>
</ng-container>

Typscript:

import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Observable } from 'rxjs';
import { User } from 'src/app/auth/user.model';
import { UserService } from 'src/app/auth/user.service';
import { Router } from '@angular/router';
import { finalize } from 'rxjs/operators';
@Component({
selector: 'app-stalking',
templateUrl: './stalking.component.html',
styleUrls: ['./stalking.component.css']
})
export class FollowingComponent implements OnInit {
@Input() userUID: string;
userId: string;
displayedColumns = ["userName", "userTag", "userRank", "factionName", "stalking"];
dataSource = new MatTableDataSource<User>();
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;
//User Array
userArray$: Observable<unknown[]| null>;
usersUserStalking: User[] = []
//loading
isLoading: boolean = false;
constructor(private user: UserService,
private db: AngularFirestore,
private router: Router) {}
async ngOnInit() {
await this.onReadCollection(this.userUID)
}
async onReadCollection(userUID: string){
this.isLoading = true;
this.db.collection(`users/${userUID}/stalking`).get()
.pipe(
finalize(() => {
this.isLoading = false;
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
console.log(this.usersUserStalking)
this.dataSource.data = this.usersUserStalking; // update dataScource
console.log(this.dataSource.data)
})
)
.subscribe(snaps => {
snaps.forEach(snap => {
this.user.findUserbyUID(snap.id).subscribe(user => {
this.usersUserStalking.push(<User>user)
})
})
})

}

async getFriendsForProfile(){
this.userId = this.user.getUserUID();
}
ngAfterViewInit() {
// this.dataSource.sort = this.sort;
// this.dataSource.paginator = this.paginator;
// this.dataSource.data = this.usersUserStalking
}
doFilter(event: Event | null) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
navigateProfile(userTag){
this.router.navigate(['/profile', userTag])    
}
}

我的滤镜设置如下:

html:

<mat-form-field fxFlex="40%">
<input matInput (keyup)="doFilter($event)" placeholder="Ex. Username" #input>
</mat-form-field>

打印稿:

doFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}

我觉得我复制了角材质表,就像它是如何在这里显示的例子:https://material.angular.io/components/table/examples

编辑1:我更新了我的代码,让初始用户现在可见,但通常仍然有同样的问题,我只看到表中的所有用户后使用过滤器和清除过滤器。

编辑2:

我修复了这个问题,通过做这个Jank下面在ngAfterViewInit(),但我仍然想要一个更好的答案,比这个Jank我刚刚编造:

ngAfterViewInit() {
setTimeout(()=> {
this.dataSource.filter = "p";
}, 100);
setTimeout(()=> {
this.dataSource.filter = "";
}, 1000);
}

我认为这与过滤器无关。您可能看不到数据,因为您的表是用空数据呈现的。当你从onReadCollection收到数据后,你没有更新dataSource

async onReadCollection(userUID: string) {
const snapIds = await this.db.collection(`users/${userUID}/stalking`).get().map(snap => snap?.id);
for (const id of snapIds) {
let user: User = await this.user.findUserbyUID(id);
this.usersUserStalking.push(user);
}
this.dataSource.data = [...this.usersUserStalking] // update dataScource
}
把这部分大体看一遍。嵌套HTTP调用和订阅不是好的做法。此外,您正在递归地创建订阅,但从未取消订阅。你可以使用async/await模式,但我建议使用其他rxjs方法(如mergeMap)来处理异步可观察对象。

try use

this.dataSource=new MatTableDataSource(this.usersUserStalking)
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;

使用(input)not (keyup)

<input matInput (input)="doFilter($event)" ..>
changeFilter(value:any){
this.dataSource.filter = value.trim().toLowerCase();
}

这可能与ngIf条件有关。因为usersUserStalking部分是异步的,你可能想在ts文件中创建一个可观察对象,比如

$isVisible = new BehaviourSubject(false);

this.usersUserStalking.push(<User>user)之后,你可以添加这一行:this.$isVisible.next(this.usersUserStalking.length > 0 && this.isLoading == false).

在你的html中简单的*ngIf="$isVisible | async";

还有一点,我不认为你需要ngIf的ng-container,你可以把你的ngIf放在你使用的组件中,像这样:

<mat-table *ngIf="$isVisible | async" [dataSource]="dataSource" matSort>

这个问题的发生是因为它触发了finalize()内部的回调,但不会等待subscribe()内部的异步请求(获取用户详细信息),所以当将this.usersUserStalking分配给dataSource时,它当时是空数组。为了解决这个问题,我们可以使用一些操作符来流式处理请求,这可以确保在所有用户被请求后调用finalize,请尝试如下:

async onReadCollection(userUID: string) {
this.isLoading = true;
this.db.collection(`users/${userUID}/stalking`).get()
.pipe(
finalize(() => {
this.isLoading = false;
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
console.log(this.usersUserStalking);
this.dataSource.data = this.usersUserStalking; // update dataScource
console.log(this.dataSource.data);
}),
switchMap(snaps => {
const requests = snaps && snaps.length ? snaps.map(snap => {
return this.user.findUserbyUID(snap.id);
}): []
return forkJoin(requests);
})
)
.subscribe(users => {
this.usersUserStalking.push(...users);
});
}
}

最新更新