javascript - Angular Cómo filtrar datos de un arreglo buscando en un input
Cómo filtrar un objeto de array en texto de entrada - angular Estoy intentando hacer una barra de búsqueda para filtrar donde el usuario pueda buscar la ubicación/descripción, a la que llamé "sensor".
roomlist.component.ts
validateForm: FormGroup;
rowData: templogRecord[] = [];
option: any = [];
onLoad() {
this.rowData = record.default.records;
this.option = [];
this.rowData.forEach(room => {
this.option.push({
tooltip: {
formatter: "{a} <br/>{b} : {c}°"
},
toolbox: {
show: true,
feature: {
mark: { show: false },
restore: { show: false },
saveAsImage: { show: false }
}
},
series: [
{
name: room.sensor,
type: 'gauge',
center: ['40%', '70%'],
splitNumber: 10,
radius: '70%',
axisLine: {
lineStyle: {
color: [[0.2, '#48b'], [0.8, '#228b22'], [1, '#ff0000']],
width: 8
}
},
axisTick: {
splitNumber: 10,
length: 12,
lineStyle: {
color: 'auto'
}
},
axisLabel: {
textStyle: {
color: 'auto'
}
},
splitLine: {
show: true,
length: 30,
lineStyle: {
color: 'auto'
}
},
pointer: {
width: 5
},
title: {
show: true,
offsetCenter: [0, '65%'],
textStyle: {
fontWeight: 'bolder'
}
},
detail: {
formatter: '{value}°',
textStyle: {
color: 'auto',
fontWeight: 'bolder'
}
},
data: [{ value: this.tempGenerator(), name: "Temperature" }]
},
{
name: '转速',
type: 'gauge',
center: ['70%', '25%'],
splitNumber: 10,
radius: '40%',
axisLine: {
lineStyle: {
width: 8
}
},
axisTick: {
length: 12,
lineStyle: {
color: 'auto'
}
},
splitLine: {
length: 20,
lineStyle: {
color: 'auto'
}
},
pointer: {
width: 5
},
title: {
show: true,
offsetCenter: [0, '80%'],
textStyle: {
fontWeight: 'bolder',
}
},
detail: {
formatter: '{value}%',
offsetCenter: [0, '55%'],
textStyle: {
color: 'auto',
fontSize: 18,
fontWeight: 'bolder'
}
},
data: [{ value: 1.5, name: "Humidity" }]
}
]
});
});
}
tempGenerator() {
var time = 12;
var num = Math.random() * 100;
var tempBase = Math.round(num);
var fluc = [0, 1, 1, 2, 1, 1, 2.5, 3.5, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
return tempBase * fluc[time];
}
searchData(searchValue: any) {
if (searchValue.length >= 3) {
this.rowData = this.rowData.filter((data: templogRecord) => {
console.log(data['sensor']);
});
} else if (searchValue.length < 1) {
console.log('empty')
}
}
}
roomlist.json
{
"records": [
{
"dateandtime": "2018-06-14 02:24:02",
"sensor": "Nine Seal Area",
"temperature": "25.9",
"humidity": "99.9"
},
{
"dateandtime": "2018-06-14 02:24:02",
"sensor": "Ten Line2",
"temperature": "25.9",
"humidity": "99.9"
},
{
"dateandtime": "2018-06-14 02:22:01",
"sensor": "Eight Line1",
"temperature": "25.9",
"humidity": "99.9"
}
]
}
room-list.component.html
<div class="flex-container">
<div class="date-filter">
<nz-input-group [nzSuffix]="suffixIconSearch">
<input type="text"
nz-input placeholder="Search"
[(ngModel)]="filterSearch"
(ngModelChange)="searchData($event)"
/>
</nz-input-group>
<ng-template #suffixIconSearch>
<i nz-icon nzType="search"></i>
</ng-template>
</div>
<ul class="cards">
<li class="cards__item" *ngFor="let data of option">
<div class="card">
<div echarts [options]="data" [autoResize]="true"></div>
<div class="card__content">
<button class="btn btn--block card__btn">Button</button>
</div>
</div>
</li>
</ul>
</div>
En la función searchData, estoy tratando de hacer que filtre mientras se escribe basado en la ubicación/descripción, a la que le puse el nombre de "sensor".
Respuesta #1
Cada vez que haces una búsqueda, estás filtrando los elementos en tu array y dando la salida a tu array original. En consecuencia, pierdes tus datos. ¿Por qué no creas 2 variables:
- El arreglo original que no cambia (que contiene tus datos) debería estar en un proveedor, pero en nuestro ejemplo lo declararemos en tu componente.
- El arreglo filtrado que vas a mostrar
searchData(searchValue: any) {
this.filteredData = this.rowData.filter((item: templogRecord) => {
return item.sensor.toLowerCase().includes(searchValue.toLowerCase());
});
}
Respuesta #2
Recomendaría esta solución (Basado en materiales de autocompletado: https://stackblitz.com/angular/lndebkoyare?file=app%2Fautocomplete-filter-example.ts)
En tu componente:
import {Component, OnInit} from '@angular/core';
import {FormControl} from '@angular/forms';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';
/**
* @title Filter autocomplete
*/
@Component({
selector: 'autocomplete-filter-example',
templateUrl: 'autocomplete-filter-example.html',
styleUrls: ['autocomplete-filter-example.css'],
})
export class FilterExample implements OnInit {
// your control for input
searchControl = new FormControl();
// your whole set of options
options: string[] = ['One', 'Two', 'Three'];
// your current result based on filters input
filteredOptions: Observable<string[]>;
ngOnInit() {
this.filteredOptions = this.searchControl.valueChanges
.pipe(
startWith(''),
map(value => this._filter(value))
);
}
private _filter(value: string): string[] {
const filterValue = value.toLowerCase();
return this.options.filter(option => option.toLowerCase().includes(filterValue));
}
}
Tu plantilla se vería así:
<div class="flex-container">
<div class="date-filter">
<nz-input-group [nzSuffix]="suffixIconSearch">
<input type="text"
nz-input placeholder="Search"
[formControl]="searchControl"
/>
</nz-input-group>
<ng-template #suffixIconSearch>
<i nz-icon nzType="search"></i>
</ng-template>
</div>
<ul class="cards">
<li class="cards__item" *ngFor="let data of filteredOptions | async">
<div class="card">
<div echarts [options]="data" [autoResize]="true"></div>
<div class="card__content">
<button class="btn btn--block card__btn">Button</button>
</div>
</div>
</li>
</ul>
Cada vez que el valor en la entrada cambia, el observable valueChanges en searchControl emite el valor actual de este campo de entrada. Esta parte map(value => this._filter(value)) devuelve un subconjunto filtrado de tu array de opciones, que puede ser mostrado usando el pipe async: <li class="cards__item" *ngFor="let data of filteredOptions | async">...</li>
