我正在使用.net核心Web API开发一个角度项目。 在具有表的组件中,首先我使用仅适用于一个参数的全局过滤器,但是客户请求希望对过滤器更加具体,因此我决定使用过滤谓词。 我遵循了此示例https://medium.com/@sevriukovmk/angular-mat-table-filter-2ead680c57bb,但是当我开始写任何过滤器的任何输入时,控制台会说:
错误TypeError:无法读取未定义的属性'toString' 在MatTableDataSource.filterPredicate的第766行(在ts代码中,在 createFilter()函数中用粗体和斜体标记)。 我试图查看带console.log(row)的“ createFilter()”函数的行是什么,并仅向我显示对象的第一行:
所以,我不知道这样做的原因是什么。有人可以帮我吗?感谢您的建议!
带来api的对象是这样的:
0: {group: "Mayo de 2021"}
1:anio: 2021
etapa: (32) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…},
{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
fechaCreacion: null
fechaPactada: null
fechaProd: null
idCliente: 1
idClienteNavigation: {idCliente: 1, nombreCli: "SCHLUMBERGER DEL ECUADOR"}
idTipoTransfo: 4
idTipoTransfoNavigation: null
idTransfo: 2220
mes: 5
nombreCli: "SCHLUMBERGER DEL ECUADOR"
nucleos: "c"
oPe: 2482
oTe: 11624
observaciones: null
potencia: 500
prioridad: 0
rangoFin: 2
rangoInicio: 2
__proto__: Object
2: {idTransfo: 2256, oPe: 258, oTe: 369, observaciones: null, rangoInicio: 200, …}
3: {idTransfo: 2258, oPe: 654, oTe: 3210, observaciones: "second proof", rangoInicio: 300, …}
4: {idTransfo: 2260, oPe: 7913, oTe: 3031, observaciones: null, rangoInicio: 1, …}
5: {idTransfo: 2255, oPe: 1973, oTe: 2021, observaciones: "proof", rangoInicio: 2, …}
6: {group: "Octubre de 2020"}
7: {idTransfo: 2250, oPe: 159753, oTe: 159753, observaciones: "lago", rangoInicio: 0, …}
ts组件是这样的:
import { Component, OnInit, Inject,ViewChild, Input, Output,EventEmitter, NgZone } from '@angular/core';
import { Transformadores } from '../models/transformadores';
import { TransformadoresService } from '../services/transformadores.service';
import { ActivatedRoute } from '@angular/router';
import { ErrorStateMatcher } from '@angular/material/core';
import { FormControl, FormGroupDirective, NgForm, Validators, FormBuilder, FormGroup } from '@angular/forms';
import {
MatDialog,
MatDialogRef,
MAT_DIALOG_DATA,
MatDialogConfig
} from "@angular/material/dialog";
import { ClienteService } from '../services/cliente.service';
import { Cliente } from '../models/cliente';
import { TipoTransfo} from '../models/tipoTransfo';
import { MatSnackBar } from '@angular/material/snack-bar';
import {MatSort} from '@angular/material/sort';
import {MatTableDataSource, MatTable} from '@angular/material/table';
import { EtapaService } from '../services/etapa.service';
import { Etapa } from '../models/etapa';
import { TipoEtapaService } from '../services/tipo-etapa.service';
import {TipoEtapa} from '../models/tipoEtapa';
import { Observable, forkJoin } from 'rxjs';
import { tap, take } from 'rxjs/operators';
import { TransformadoresEtapas } from '../models/transformadoresEtapas';
import { Vista } from '../models/Vista';
import { TipoTransfoService } from '../services/tipoTransfo';
import { ExcelService } from '../services/excel.service';
import { Colores } from '../models/colores';
import { ColoresService } from '../services/colores.service';
import { EtapaTransfo } from '../models/etapaTransfo';
import {map, startWith} from 'rxjs/operators';
import * as jQuery from 'jquery';
import { MatPaginator } from '@angular/material';
const MAP_NOMBRE_ETAPA: { [tipoEtapa: string]: number} = {
"documentacion":1,
"bobinaBT1":2,
"bobinaBT2":3,
"bobinaBT3":4,
"bobinaAT1":5,
"bobinaAT2":6,
"bobinaAT3":7,
"bobinaRG1":8,
"bobinaRG2":9,
"bobinaRG3":10,
"bobinaRF1":11,
"bobinaRF2":12,
"bobinaRF3":13,
"ensamblajeBobinas":14,
"corteYPlegadoPYS":15,
"soldaduraPYS":16,
"envioPYS":17,
"nucleo":18,
"montaje":19,
"horno":20,
"cYPTapaCuba":21,
"tapa":22,
"radiadoresOPaneles":23,
"cuba":24,
"tintasPenetrantes":25,
"granallado":26,
"pintura":27,
"encubado":28,
"ensayosRef":29,
"terminacion":30,
"envioADeposito":31,
"envioACliente":32
}
@Component({
selector: 'etapa-column-component',
template: `
<ng-container *ngIf="etapa">
<div style="height:64px;line-height:64px" [style.background-color] = "etapa.idColorNavigation ? etapa.idColorNavigation.codigoColor : 'white'" [matTooltip]="etapa.idColorNavigation ? etapa.idColorNavigation.leyenda : '' ">
<span style="padding-left:10px;" *ngIf="etapa.dateFin" >{{etapa.dateFin | date:'dd/MM/yyyy'}}</span>
<span style="padding-left:10px;" *ngIf="(etapa.tiempoParc)!='Finalizada' && (etapa.tiempoParc)!=null" >{{etapa.tiempoParc}}</span>
<span>
<button mat-icon-button *ngIf="!etapa.dateIni" style="line-height:64px" (click)=asignarRef(etapa) matTooltip="Asignar referencia"><mat-icon>done</mat-icon></button>
</span>
<!--<span ></span>-->
</div>
</ng-container>
`,
styleUrls: ['./transformadores-reloaded.component.css']
})
export class EtapaColumnComponent{
coloresArr:Colores[]=[];
etapaSelected:Etapa;
@Input() etapa:Etapa; actualizar:Boolean;
@Output() actualizado=new EventEmitter<Boolean>();
constructor(){}
}
@Component({
selector: 'app-transformadores-reloaded',
templateUrl: './transformadores-reloaded.component.html',
styleUrls: ['./transformadores-reloaded.component.css']
})
export class TransformadoresReloadedComponent implements OnInit {
isLoadingResults = true;
dataGetTrafos:MatTableDataSource<any>;
dataExcel:TransformadoresEtapas[];
data3:Cliente[]=[];
data4:Etapa[]=[];
diego:ComboClientes[]=[];
idTransfo:number;
durationInSeconds=3;
data2:Transformadores;
data5:Etapa[]=[];
data6:TipoEtapa[]=[];
data7:EtapaTransfo[]=[];
mensajeSnack:string;
arrayBool:boolean;
muestre:boolean=false;
vista:Vista[];
dataTipoTransfo:ComboTipoTransfo[]=[];
data8TipoTransfo:TipoTransfo[]=[];
colores:Colores[]=[];
displayedColumns1:string[]=['Accion']
displayedColumns2:string[]=[
'oTe',
'nucleos',
'oPe',
'rangoInicio',
'rangoFin',
'observaciones',
'potencia',
'nombreCli',
'fechaPactada',
'fechaProd'
]
//
etapasColumns: string[]= Object.keys(MAP_NOMBRE_ETAPA);
// TODAS las columnas
allColumns: string[]= this.displayedColumns1.concat(this.displayedColumns2).concat(this.etapasColumns);
dataSource;
etapasActualizadas:boolean;
form=new FormGroup(
{
oTe:new FormControl(),
nucleos:new FormControl(),
oPe :new FormControl(),
rangoInicio :new FormControl(),
rangoFin:new FormControl(),
observaciones:new FormControl(),
potencia :new FormControl(),
nombreCli :new FormControl(),
fechaPactada:new FormControl(),
fechaProd:new FormControl(),
}
)
oTe= '';
nucleos='';
oPe= '';
rangoInicio= '';
rangoFin= '';
observaciones= '';
potencia= '';
nombreCli= '';
// fechaPactada= '';
// fechaProd: ''
@ViewChild(MatSort, {static: true}) sort: MatSort;
@ViewChild(MatTable, { static: false }) matTable: MatTable<any>;
@ViewChild(MatPaginator) paginator: MatPaginator;
constructor(private ngZone: NgZone,private transformadoresService: TransformadoresService, private
clientesService: ClienteService, public dialog: MatDialog,private route: ActivatedRoute,private
_snackBar: MatSnackBar,private etapaService: EtapaService, private tipoEtapaService: TipoEtapaService,
private tipoTransfoService: TipoTransfoService, private excelService: ExcelService,private
coloresService:ColoresService) {}
ngAfterViewInit() {
this.ngZone.onMicrotaskEmpty.pipe(take(5)).subscribe(()=>this.matTable.updateStickyColumnStyles());
}
ngOnInit(): void {
this.dataGetTrafos=new MatTableDataSource();
this.getTrafos();
this.dataGetTrafos.filterPredicate =this.createFilter();
this.dataGetTrafos.paginator = this.paginator;
this.dataGetTrafos.sort = this.sort;
this.getClientes();
this.getTipoTransfo();
}
//This is for get Etapas from etapa in every object
getEtapa(t:Transformadores, nombreEtapa: string): any {
let matchEtapa = t.etapa.filter(etapa => etapa.idTipoEtapa == MAP_NOMBRE_ETAPA[nombreEtapa]);
if(matchEtapa.length!=0)
{
return matchEtapa[0];
}
if(this.etapasActualizadas==true)
{
this.getTrafos();
}
}
actualizar(evento:any){
if(evento==true)
{
this.getTrafos();
}
}
getTrafos():void{
this.transformadoresService.getTrafos()
.subscribe(transfo => {
console.log(transfo);
this.isLoadingResults = true;
this.dataGetTrafos.data=transfo;
}, err => {
this.isLoadingResults = false;
},
() =>{
this.isLoadingResults=false;
}
);
}
isGroup(index, item): boolean{
return item.group;
}
//THIS IS THE FILTER
createFilter() {
return (row: any, filters: string) => {
console.log(row);
console.log(filters);
// split string per '$' to array
const filterArray = filters.split('$');
const oTe = filterArray[0];
const nucleos = filterArray[1];
const oPe = filterArray[2];
const rangoInicio = filterArray[3];
const rangoFin = filterArray[4];
const observaciones = filterArray[5];
const potencia = filterArray[6];
const nombreCli = filterArray[7];
const matchFilter = [];
// Fetch data from row
const columnOTe = row.oTe;
const columnNucleos = row.nucleos;
const columnOPe = row.oPe;
const columnRangoInicio = row.rangoInicio;
const columnRangoFin = row.rangoFin;
const columnObservaciones = row.observaciones;
const columnPotencia = row.potencia;
const columnNombreCli = row.nombreCli;
***THIS IS THE LINE WHERE IS THE ERROR***
// verify fetching data by our searching values
const customFilterOTe = columnOTe.toString().toLowerCase().includes(oTe);
const customFilterNucleos = columnNucleos.toLowerCase().includes(nucleos);
const customFilterOPe = columnOPe.toString().toLowerCase().includes(oPe);
const customFilterRangoInicio = columnRangoInicio.toString().toLowerCase().includes(rangoInicio);
const customFilterRangoFin = columnRangoFin.toString().toLowerCase().includes(rangoFin);
const customFilterObservaciones = columnObservaciones.toLowerCase().includes(observaciones);
const customFilterPotencia = columnPotencia.toString().toLowerCase().includes(potencia);
const customFilterNombreCli = columnNombreCli.toLowerCase().includes(nombreCli);
// push boolean values into array
matchFilter.push(customFilterOTe);
matchFilter.push(customFilterNucleos);
matchFilter.push(customFilterOPe);
matchFilter.push(customFilterRangoInicio);
matchFilter.push(customFilterRangoFin);
matchFilter.push(customFilterObservaciones);
matchFilter.push(customFilterPotencia);
matchFilter.push(customFilterNombreCli);
// return true if all values in array is true
// else return false
return matchFilter.every(Boolean);
};
}
applyFilter() {
const ot =this.form.get('oTe').value;
const nucl=this.form.get('nucleos').value;
const op=this.form.get('oPe').value;
const rI=this.form.get('rangoInicio').value;
const rF=this.form.get('rangoFin').value;
const obs=this.form.get('observaciones').value;
const pot=this.form.get('potencia').value;
const nC=this.form.get('nombreCli').value;
this.oTe = ot === null ? '' : ot;
this.nucleos = nucl === null ? '' : nucl;
this.oPe = op === null ? '' : op;
this.rangoInicio = rI === null ? '' : rI;
this.rangoFin = rF === null ? '' : rF;
this.observaciones = obs === null ? '' : obs;
this.potencia = pot === null ? '' : pot;
this.nombreCli = nC === null ? '' : nC;
// create string of our searching values and split if by '$'
const filterValue = this.oTe + '$' + this.nucleos + '$' + this.oPe+'$' + this.rangoInicio+'$' + this.rangoFin+'$' + this.observaciones+'$' + this.potencia+'$' + this.nombreCli;
this.dataGetTrafos.filter = filterValue.trim().toLowerCase();
console.log("THIS DATA GET TRAFOS: ",this.dataGetTrafos.filter);
}
}
html是这样的:
<mat-card class="titulo">
<mat-card-header>
<mat-card-title style="line-height:60px;">Transformadores</mat-card-title>
</mat-card-header>
<br>
</mat-card>
<div class="example-container mat-elevation-z8">
<div class="example-loading-shade"
*ngIf="isLoadingResults">
<mat-spinner *ngIf="isLoadingResults"></mat-spinner>
</div>
<!--Tabla transformadores-->
<div class="float " style="bottom:7vh;">
<button mat-fab color="primary" (click)="dialogAddTransfo()" >
<mat-icon>add</mat-icon>
</button>
</div>
<div class="float ">
<button mat-fab color="primary" (click)="export()">
<mat-icon><svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="24" height="24"
viewBox="0 0 172 172"
style=" fill:#000000;"><g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><path d="M0,172v-172h172v172z" fill="none"></path><g fill="#ffffff"><path d="M86,21.5l-71.66667,14.33333v100.33333l71.66667,14.33333zM100.33333,35.83333v14.33333h14.33333v14.33333h-14.33333v14.33333h14.33333v14.33333h-14.33333v14.33333h14.33333v14.33333h-14.33333v14.33333h50.16667c3.956,0 7.16667,-3.21067 7.16667,-7.16667v-86c0,-3.956 -3.21067,-7.16667 -7.16667,-7.16667zM129,50.16667h14.33333v14.33333h-14.33333zM29.92643,59.46094h12.73763l6.62077,15.87305c0.5375,1.29717 0.94208,2.80149 1.35775,4.50716h0.18197c0.2365,-1.02483 0.7179,-2.59064 1.44173,-4.63314l7.37663,-15.74707h11.61784l-13.87142,26.30111l14.27734,26.77702h-12.3877l-7.97852,-17.30078c-0.301,-0.60917 -0.65799,-1.83567 -0.95182,-3.54134h-0.11198c-0.17917,0.817 -0.5403,2.04015 -1.0778,3.68132l-8.0485,17.16081h-12.44368l14.76725,-26.56706zM129,78.83333h14.33333v14.33333h-14.33333zM129,107.5h14.33333v14.33333h-14.33333z"></path></g></g></svg></mat-icon>
</button>
</div>
<table mat-table [dataSource]="dataGetTrafos" id="tabla">
<ng-container matColumnDef="Accion" id="Accion" sticky>
<th mat-header-cell *matHeaderCellDef > Accion </th>
<td mat-cell *matCellDef="let row" >
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Example icon-button with a menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-icon-button class="editBorr" color="primary" (click)="dialogEditTransfo(row)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button style="color:teal;" class="editBorr" (click)="onRowClicked(row)" matTooltip="Procesos">
<mat-icon>av_timer</mat-icon>
</button>
<button mat-icon-button color="warn" class="editBorr" (click)="dialogDeleteTransfo(row)" >
<mat-icon>delete</mat-icon>
</button>
</mat-menu>
</td>
</ng-container>
<ng-container [formGroup]="form" *ngFor="let column of displayedColumns2" sticky matColumnDef="{{column}}">
<th mat-header-cell *matHeaderCellDef style="width:100px!important;padding-left:10px!important;text-align:center">
{{column}}
<mat-form-field style="width:50px;" floatLabel="never">
<mat-label>{{column}}</mat-label>
<input matInput [formControlName]="column" (keyup)="applyFilter()">
</mat-form-field>
</th>
<td mat-cell *matCellDef="let element"> {{column=='fechaPactada'|| column=='fechaProd' ? (element[column] | date:'dd/MM/yyyy') : (element[column])}} </td>
</ng-container>
<ng-container *ngFor="let column of etapasColumns;" matColumnDef="{{column}}" >
<th mat-header-cell *matHeaderCellDef style="padding:20px!important">
{{column}}
</th>
<td mat-cell *matCellDef="let element" >
<etapa-column-component [etapa]="getEtapa(element, column)" (actualizado)="actualizar($event)">
</etapa-column-component>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="allColumns;sticky: true" ></tr>
<tr mat-row *matRowDef="let row; columns: allColumns;"></tr>
<ng-container matColumnDef="groupHeader">
<td mat-cell *matCellDef="let row" colspan="999" style="width:100%;background-color:rgb(247,150,70)!important;text-align:left"><div class="grupo" style="margin-left:15px;"><strong>{{row.group}}</strong></div></td>
</ng-container>
<tr mat-row *matRowDef="let row; columns: ['groupHeader']; when: isGroup"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 100]" showFirstLastButtons></mat-paginator>
</div>