Material table 不更新 @Input 的新值
Material table doesn't update with new values of @Input
我有一个 Angular 组件正在使用 @Input
(搜索结果),我想将其用作 Angular Material table 的数据源。
不幸的是,table 似乎无法识别 @Input
中的变量何时更改并且始终保持为空。
我的工作流程是这样的:
- 主视图由 2 个部分组成:搜索和搜索结果。
- search 定义搜索参数并从搜索服务获取结果。
- search 通知 main 它有一个新结果并且 main 存储结果在一个变量中。
- search-result 获取变量作为@Input 并用结果更新table。
一切正常,直到 console.log(this.passengerSearchReadModels);
打印出正确的结果,但最后一步(更新 table)没有 :(
main.html
<div class="mx-5">
<app-search (notify)="onSearch($event)"></app-search>
<app-search-result [passengerSearchReadModels]="passengerSearchReadModels"></app-search-result>
</div>
main.ts
@Component({
selector: 'app-main',
templateUrl: './main.component.html',
styleUrls: ['./main.component.scss']
})
export class MainComponent implements OnInit {
passengerSearchReadModels: PassengerSearchReadModel[] = [];
constructor() { }
ngOnInit(): void {
}
onSearch(passengerSearchReadModels: PassengerSearchReadModel[]): void {
console.log('in onSearch');
this.passengerSearchReadModels = passengerSearchReadModels;
console.log(this.passengerSearchReadModels); // here the correct result is displayed in the console
}
}
search.ts
@Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {
@Output() notify: EventEmitter<PassengerSearchReadModel[]> = new EventEmitter<PassengerSearchReadModel[]>();
searchQuery: SearchQuery;
passengerSearchReadModels: PassengerSearchReadModel[] = [];
constructor(private searchService: SearchService) {
this.searchQuery = {
lastName: null
};
this.init();
}
ngOnInit(): void {
}
init(): void {
}
search(): void {
this.searchService.getPassengers(this.searchQuery)
.subscribe(result => {
console.log(result);
this.passengerSearchReadModels.push(result);
}, error => console.error(error));
this.notify.emit(this.passengerSearchReadModels);
}
}
搜索-result.html:
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="fullName">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name, Vorname</th>
<td mat-cell *matCellDef="let element">{{element.lastName}}, {{element.firstName}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
搜索-result.ts
@Component({
selector: 'app-search-result',
templateUrl: './search-result.component.html',
styleUrls: ['./search-result.component.scss']
})
export class SearchResultComponent implements AfterViewInit {
@Input() passengerSearchReadModels: PassengerSearchReadModel[] = [];
@ViewChild(MatSort, { static: true }) sort: MatSort;
displayedColumns: string[] = [ColumnNames.FullName];
dataSource = new MatTableDataSource<PassengerSearchReadModel>(this.passengerSearchReadModels);
selection = new SelectionModel<PassengerSearchReadModel>(true, []);
constructor() {
}
ngAfterViewInit(): void {
this.dataSource.sortingDataAccessor = this.sortingDataAccessor;
this.dataSource.sort = this.sort;
}
// sorting deleted bc irrelevant
}
#编辑
search.html
<div class="shadow">
<div class="row">
<div class="col-2">
<mat-form-field>
<mat-label>{{ "search.lastname" | translate }}</mat-label>
<input matInput type="text" max="100" [(ngModel)]="searchQuery.lastName" />
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<button mat-stroked-button color="primary" (click)="search()">
<span class="material-icons mr-2">search</span>
{{ "search.searchButton" | translate }}
</button>
</div>
<div class="col-3"></div>
</div>
</div>
searchService.ts
@Injectable({
providedIn: 'root'
})
export class SearchService {
private ENDPOINT_GET = 'Passenger';
constructor(private http: HttpClient) { }
public getPassengers(searchQuery: SearchQuery): Observable<PassengerSearchReadModel> {
let params = new HttpParams();
if (searchQuery.lastName) { params = params.append('lastName', searchQuery.lastName); }
return this.http.get<PassengerSearchReadModel>(environment.API_URL + this.ENDPOINT_GET, { params });
}
}
this.sortingDataAccessor
sortingDataAccessor(item: any, property: string): any {
const columnSortingDataAccessors = ColumnSortingDataAccessor.get();
let sortingDataAccessor: string;
switch (property) {
// cases omitted for readability
default: {
sortingDataAccessor = columnSortingDataAccessors[property];
break;
}
}
return item[sortingDataAccessor];
}
我必须更改什么才能使 table 更新为新值?
我在你的代码中发现了一些问题,首先你需要在加载结果后发出结果,如下面的代码
search(): void {
this.searchService.getPassengers(this.searchQuery)
.subscribe(result => {
this.notify.emit(result );
}, error => console.error(error));
}
其次,每次数据改变时,你需要初始化新的table源,或者你只需要改变数据的数据源table (mat-table)
onSearch(passengerSearchReadModels): void {
this.passengerSearchReadModels = new MatTableDataSource<any>(passengerSearchReadModels);
}
或
onSearch(passengerSearchReadModels): void {
this.passengerSearchReadModels.data = passengerSearchReadModels;
}
你可以查看演示Here
我有一个 Angular 组件正在使用 @Input
(搜索结果),我想将其用作 Angular Material table 的数据源。
不幸的是,table 似乎无法识别 @Input
中的变量何时更改并且始终保持为空。
我的工作流程是这样的:
- 主视图由 2 个部分组成:搜索和搜索结果。
- search 定义搜索参数并从搜索服务获取结果。
- search 通知 main 它有一个新结果并且 main 存储结果在一个变量中。
- search-result 获取变量作为@Input 并用结果更新table。
一切正常,直到 console.log(this.passengerSearchReadModels);
打印出正确的结果,但最后一步(更新 table)没有 :(
main.html
<div class="mx-5">
<app-search (notify)="onSearch($event)"></app-search>
<app-search-result [passengerSearchReadModels]="passengerSearchReadModels"></app-search-result>
</div>
main.ts
@Component({
selector: 'app-main',
templateUrl: './main.component.html',
styleUrls: ['./main.component.scss']
})
export class MainComponent implements OnInit {
passengerSearchReadModels: PassengerSearchReadModel[] = [];
constructor() { }
ngOnInit(): void {
}
onSearch(passengerSearchReadModels: PassengerSearchReadModel[]): void {
console.log('in onSearch');
this.passengerSearchReadModels = passengerSearchReadModels;
console.log(this.passengerSearchReadModels); // here the correct result is displayed in the console
}
}
search.ts
@Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {
@Output() notify: EventEmitter<PassengerSearchReadModel[]> = new EventEmitter<PassengerSearchReadModel[]>();
searchQuery: SearchQuery;
passengerSearchReadModels: PassengerSearchReadModel[] = [];
constructor(private searchService: SearchService) {
this.searchQuery = {
lastName: null
};
this.init();
}
ngOnInit(): void {
}
init(): void {
}
search(): void {
this.searchService.getPassengers(this.searchQuery)
.subscribe(result => {
console.log(result);
this.passengerSearchReadModels.push(result);
}, error => console.error(error));
this.notify.emit(this.passengerSearchReadModels);
}
}
搜索-result.html:
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="fullName">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name, Vorname</th>
<td mat-cell *matCellDef="let element">{{element.lastName}}, {{element.firstName}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
搜索-result.ts
@Component({
selector: 'app-search-result',
templateUrl: './search-result.component.html',
styleUrls: ['./search-result.component.scss']
})
export class SearchResultComponent implements AfterViewInit {
@Input() passengerSearchReadModels: PassengerSearchReadModel[] = [];
@ViewChild(MatSort, { static: true }) sort: MatSort;
displayedColumns: string[] = [ColumnNames.FullName];
dataSource = new MatTableDataSource<PassengerSearchReadModel>(this.passengerSearchReadModels);
selection = new SelectionModel<PassengerSearchReadModel>(true, []);
constructor() {
}
ngAfterViewInit(): void {
this.dataSource.sortingDataAccessor = this.sortingDataAccessor;
this.dataSource.sort = this.sort;
}
// sorting deleted bc irrelevant
}
#编辑 search.html
<div class="shadow">
<div class="row">
<div class="col-2">
<mat-form-field>
<mat-label>{{ "search.lastname" | translate }}</mat-label>
<input matInput type="text" max="100" [(ngModel)]="searchQuery.lastName" />
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<button mat-stroked-button color="primary" (click)="search()">
<span class="material-icons mr-2">search</span>
{{ "search.searchButton" | translate }}
</button>
</div>
<div class="col-3"></div>
</div>
</div>
searchService.ts
@Injectable({
providedIn: 'root'
})
export class SearchService {
private ENDPOINT_GET = 'Passenger';
constructor(private http: HttpClient) { }
public getPassengers(searchQuery: SearchQuery): Observable<PassengerSearchReadModel> {
let params = new HttpParams();
if (searchQuery.lastName) { params = params.append('lastName', searchQuery.lastName); }
return this.http.get<PassengerSearchReadModel>(environment.API_URL + this.ENDPOINT_GET, { params });
}
}
this.sortingDataAccessor
sortingDataAccessor(item: any, property: string): any {
const columnSortingDataAccessors = ColumnSortingDataAccessor.get();
let sortingDataAccessor: string;
switch (property) {
// cases omitted for readability
default: {
sortingDataAccessor = columnSortingDataAccessors[property];
break;
}
}
return item[sortingDataAccessor];
}
我必须更改什么才能使 table 更新为新值?
我在你的代码中发现了一些问题,首先你需要在加载结果后发出结果,如下面的代码
search(): void {
this.searchService.getPassengers(this.searchQuery)
.subscribe(result => {
this.notify.emit(result );
}, error => console.error(error));
}
其次,每次数据改变时,你需要初始化新的table源,或者你只需要改变数据的数据源table (mat-table)
onSearch(passengerSearchReadModels): void {
this.passengerSearchReadModels = new MatTableDataSource<any>(passengerSearchReadModels);
}
或
onSearch(passengerSearchReadModels): void {
this.passengerSearchReadModels.data = passengerSearchReadModels;
}
你可以查看演示Here