Angular 5中使用排序与过滤管道后表格不更新问题求助
问题分析与解决方案
我一眼就看出问题所在了——这是Angular纯管道的特性加上你排序时原地修改数组导致的!
核心原因
- Angular纯管道的特性:默认情况下,Angular的管道是纯管道,只有当输入的引用发生变化时才会重新执行。当你添加
filterCompany管道后,若它返回的数组和原数组引用一致,后续的orderByDate管道就算排序了数组,只要引用没改,Angular就会认为数据没变化,不会更新视图。 - 原地修改数组:你的
orderByDate管道里用了value.sort(),这个方法是原地修改原数组的,不会创建新数组。也就是说,排序前后数组的引用完全一样,Angular的变更检测机制根本察觉不到数据有变化,自然不会更新表格。
具体修复步骤
1. 修改orderByDate管道,创建数组副本再排序
把排序逻辑改成先复制原数组,再对副本排序,这样每次排序都会返回新的数组引用,触发Angular的变更检测:
transform(value: Array<any>, args?: any): any { if (value == null) { return null; } // 先创建原数组的副本,避免原地修改 const valueCopy = [...value]; let valueSort = []; if (args && args == 'desc') { valueSort = this.sortByDesc(valueCopy); } else if (args && args == 'asc') { valueSort = this.sortByAsc(valueCopy); } else { valueSort = this.sortByDesc(valueCopy); } return valueSort; } sortByDesc(value) { // 这里排序的是副本,不会影响原数组 return value.sort((a: any, b: any) => { const date1 = new Date(a.ObjectCreated); const date2 = new Date(b.ObjectCreated); if (date1 < date2) { return 1; } else if (date1 > date2) { return -1; } else { return 0; } }); } sortByAsc(value) { return value.sort((a: any, b: any) => { const date1 = new Date(a.ObjectCreated); const date2 = new Date(b.ObjectCreated); if (date1 > date2) { return 1; } else if (date1 < date2) { return -1; } else { return 0; } }); }
2. 确保filterCompany管道也返回新数组
检查你的filterCompany管道,确保它过滤时返回新数组(比如用filter方法,这个方法本身就返回新数组),而不是修改原数组。示例写法如下:
transform(companies: any[], nameFilter: string, dateFilter: string): any[] { if (!companies) return []; let filtered = [...companies]; // 姓名过滤逻辑 if (nameFilter) { filtered = filtered.filter(company => company.Name.toLowerCase().includes(nameFilter.toLowerCase()) ); } // 日期过滤逻辑 if (dateFilter) { // 这里根据你的dateCreated格式调整过滤逻辑 filtered = filtered.filter(company => company.ObjectCreated.includes(dateFilter) ); } return filtered; }
3. (推荐)把排序和过滤逻辑移到组件类中
其实Angular官方不推荐用管道做复杂的过滤和排序,因为纯管道的特性很容易导致这类问题。你可以把逻辑移到组件里,更直观也更可控:
组件类代码:
filteredCompanies: any[] = []; sortDirection: 'asc' | 'desc' = 'desc'; ngOnInit() { this.updateFilteredCompanies(); } // 监听过滤条件变化,重新计算 ngOnChanges(changes: SimpleChanges) { if (changes.companies || changes.nameCompany || changes.dateCreated) { this.updateFilteredCompanies(); } } sortByDate() { this.sortDirection = this.sortDirection === 'desc' ? 'asc' : 'desc'; this.updateFilteredCompanies(); } sortByName() { // 这里补充姓名排序逻辑,类似日期排序的写法 this.updateFilteredCompanies(); } updateFilteredCompanies() { if (!this.companies) return; // 第一步:过滤 let result = [...this.companies]; if (this.nameCompany) { result = result.filter(company => company.Name.toLowerCase().includes(this.nameCompany.toLowerCase()) ); } if (this.dateCreated) { result = result.filter(company => company.ObjectCreated.includes(this.dateCreated) ); } // 第二步:排序 result.sort((a, b) => { if (this.currentSortKey === 'date') { const date1 = new Date(a.ObjectCreated); const date2 = new Date(b.ObjectCreated); return this.sortDirection === 'desc' ? date2.getTime() - date1.getTime() : date1.getTime() - date2.getTime(); } else { // 姓名排序逻辑 return this.sortDirection === 'desc' ? b.Name.localeCompare(a.Name) : a.Name.localeCompare(b.Name); } }); this.filteredCompanies = result; }
修改后的HTML模板:
<h2 class="h5 mb-1">Results ({{filteredCompanies.length}})</h2> <table class="table table-bordered table-hover table-striped"> <thead> <tr> <th>Date Created <i class="fa fa-sort" aria-hidden="true" (click)="sortByDate()"></i></th> <th>Name <i class="fa fa-sort" aria-hidden="true" (click)="sortByName()"></i></th> <th></th> </tr> <tr> <td> <input type="text" [(ngModel)]="dateCreated" name="dateCreared" class="form-control" (input)="updateFilteredCompanies()"> </td> <td> <input type="text" [(ngModel)]="nameCompany" name="name" #nameCompanyInput class="form-control" (input)="updateFilteredCompanies()"> </td> <td></td> </tr> </thead> <tbody> <tr *ngFor="let company of filteredCompanies" (click)="goEditPage(company.ObjectID) "> <td>{{ company.ObjectCreated | date:chartDate }}</td> <td>{{ company.Name }}</td> <td class="text-center "> <a class="btn btn-primary "> <i class="fa fa-angle-double-right "></i> </a> </td> </tr> </tbody> </table> <p *ngIf="filteredCompanies.length==0 ">No data !</p>
内容的提问来源于stack exchange,提问作者beginerdeveloper
相关产品推荐
相关产品推荐

