问题
I'm a new developper in angular2 and I want to do a global search in an array of json objects. For example, this array :
invoiceList =
[
{
invoiceNumber: 1234,
invoiceSupplier: "test",
invoiceStatus: "Import error",
invoiceCategory: "invoice with GR",
date: "22/01/2017",
amount : 134527
},
...
];
And I want to do my search like that :
The problem and the difficulty here is that :
- I want to search depending only on some values (ex : status, supplier name, number...) and display OTHER fields (like date, net amount etc..).
- I want to order by the final results depending on some values (ex: number, supplier, date and amount). And I don't how to do that in angular2.
- Finally, I want to do an "equivalent" of ng-show in angular2? I mean that I want to display the table only if we press search button, and if we click on cancel, it will remove it.
I know that it was simple to do that in angular 1, we can use filters, 'orderBy' and things like that but apparently in angular2, we can't do that and I got very very confused. Can you help me to solve that please???
here is my component code :
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-search',
templateUrl: './search.component.html'
})
export class SearchComponent implements OnInit {
invoiceList = [{invoiceNumber: 1234, invoiceSupplier : "test", invoiceStatus : "Import error", invoiceCategory: "invoice with GR", date : "22/01/2017", amount : 134527},
{invoiceNumber: 15672, invoiceSupplier : "test11", invoiceStatus : "Import error", invoiceCategory: "invoice without PO", date : "02/01/2017", amount : 134.3},
{invoiceNumber: 99863, invoiceSupplier : "test22", invoiceStatus : "Other Document", invoiceCategory: "invoice with GR", date : "10/12/2016", amount : 189},
{invoiceNumber: 24561, invoiceSupplier : "test50", invoiceStatus : "Other Document", invoiceCategory: "invoice without PO", date : "15/01/2017", amount : -134527},
];
constructor() { }
ngOnInit() {
}
}
and my html code :
<form>
<table>
<tr>
<td>Invoice Number :</td>
<td>
<input name="invoiceNumber">
</td>
<td>Invoice Supplier Name :</td>
<td>
<input name="invoiceSupplier">
</td>
</tr>
<tr>
<td>Invoice Status :</td>
<td>
<select name="invoiceStatus">
<option></option>
<option> Import error </option>
<option> Invoice control required </option>
<option>Rejected from SAP </option>
<option>Other Document </option>
<option> Invoice created manually in SAP </option>
<option>To be integrated in SAP </option>
<option> Integrated in SAP </option>
<option> Booked in SAP </option>
<option>Paid in SAP</option>
</select>
</td>
<td>Invoice Category :</td>
<td>
<select name="invoiceCategory">
<option></option>
<option>Invoice with GR</option>
<option>Invoice without GR</option>
<option>Invoice without PO</option>
</select>
</td>
</tr>
<tr>
<td>Order :</td>
<td>
<select name="order">
<option> Number </option>
<option> Supplier </option>
<option> Date </option>
<option> Net Amount </option>
</select>
</td>
</tr>
<tr>
<td>
<button type="submit">Search</button>
</td>
<td>
<div class="detail">
<button type="reset">Cancel</button>
</div>
</td>
</tr>
</table>
</form>
I know that I didn't do anything so far, but I'm really new at angular2, and I really got confused. Can you help me please at least with the component part???
Thank you in advance !
回答1:
DONE !! - see@PLUNKER
@Component({
selector: 'app-search',
templateUrl: 'src/search.component.html'
})
export class SearchComponent{
invoiceList = [
{invoiceNumber: 1234, invoiceSupplier : "test", invoiceStatus : "Import error", invoiceCategory: "invoice with GR", date : "22/01/2017", amount : 134527},
{invoiceNumber: 15672, invoiceSupplier : "test11", invoiceStatus : "Import error", invoiceCategory: "invoice without PO", date : "02/01/2017", amount : 134.3},
{invoiceNumber: 99863, invoiceSupplier : "test22", invoiceStatus : "Other Document", invoiceCategory: "invoice with GR", date : "10/12/2016", amount : 189},
{invoiceNumber: 24561, invoiceSupplier : "test50", invoiceStatus : "Other Document", invoiceCategory: "invoice without PO", date : "15/01/2017", amount : -134527},
];
invoiceCats = [];
invoiceStatuses = [];
invoiceNumbers = [];
invoiceFields = Object.keys(this.invoiceList[0]);
invoiceStatus = "";
invoiceCategory = "";
invoiceNumber;
invoiceSupplier;
order = this.invoiceFields[0];
searchResults = [];
constructor() {
this.invoiceList.forEach(i => {
if(this.invoiceCats.indexOf(i.invoiceCategory) === -1) {
this.invoiceCats.push(i.invoiceCategory);
}
if(this.invoiceStatuses.indexOf(i.invoiceStatus) === -1) {
this.invoiceStatuses.push(i.invoiceStatus);
}
this.invoiceNumbers.push(i.invoiceNumber);
})
}
ngOnInit() {
}
searchNow(e) {
e.preventDefault();
this.searchResults = this.invoiceList.filter(i => {
return (this.invoiceStatus ? i.invoiceStatus === this.invoiceStatus : true)
&& (this.invoiceNumber ? i.invoiceNumber === this.invoiceNumber : true)
&& (this.invoiceSupplier ? i.invoiceSupplier === this.invoiceSupplier : true)
&& (this.invoiceCategory ? i.invoiceCategory === this.invoiceCategory : true)
}).sort((a, b) => {
if(['invoiceNumber', 'amount'].indexOf(this.order) > -1) return a[this.order] - b[this.order];
if(['invoiceSupplier', 'invoiceStatus', 'invoiceCategory'].indexOf(this.order) > -1) return (a[this.order] == [a[this.order], b[this.order]].sort()[1] ? 1 : -1);
if(this.order === 'date') {
const x = new Date(a.date.split('/').reverse().join('/'));
const y = new Date(b.date.split('/').reverse().join('/'));
return x.getTime() - y.getTime();
}
})
}
}
Note: The code inside constructor is just to generate meta Data.
<form (submit)="searchNow($event)">
<table>
<tr>
<td>Invoice Number :</td>
<td>
<input name="invoiceNumber" [(ngModel)]="invoiceNumber" type="number">
</td>
<td>Invoice Supplier Name :</td>
<td>
<input name="invoiceSupplier" [(ngModel)]="invoiceSupplier" type="text">
</td>
</tr>
<tr>
<td>Invoice Status :</td>
<td>
<select name="invoiceStatus" [(ngModel)]="invoiceStatus">
<option value="">Any</option>
<option *ngFor="let iS of invoiceStatuses" [value]="iS">{{iS}}</option>
</select>
</td>
<td>Invoice Category :</td>
<td>
<select name="invoiceCategory" [(ngModel)]="invoiceCategory">
<option value="">Any</option>
<option *ngFor="let iC of invoiceCats" [value]="iC">{{iC}}</option>
</select>
</td>
</tr>
<tr>
<td>Order By:</td>
<td>
<select name="order" [(ngModel)]="order">
<option *ngFor="let iF of invoiceFields" [value]="iF">{{iF}}</option>
</select>
</td>
</tr>
<tr>
<td>
<button type="submit">Search</button>
</td>
<td>
<div class="detail">
<button type="reset">Cancel</button>
</div>
</td>
</tr>
</table>
</form>
<div>
<ul>
<li *ngFor="let i of searchResults">Number: {{i.invoiceNumber}}, Supplier: {{i.invoiceSupplier}}, Date: {{i.date}}</li>
</ul>
</div>
Note: There are many if not hundreds of ways to play with forms in Angular2
you can use whichever you like, I just used the easiest one.
回答2:
Not complete but to give you the base ...
import { Component, OnInit } from '@angular/core';
export class Invoice {
invoiceNumber: number;
invoiceSupplier: string;
invoiceStatus: string;
invoiceCategory: string;
date: string;
amount: number
}
@Component({
moduleId: module.id,
selector: 'my-app',
template: `
<div></div>
`,
styleUrls: []
})
export class AppComponent implements OnInit {
ngOnInit(): void {
this.invoiceList = [ {invoiceNumber: 1231, invoiceSupplier: "test1", invoiceStatus: "Import error3", invoiceCategory: "invoice with GR1", date: "22/01/2017", amount : 134527 },
{invoiceNumber: 1232, invoiceSupplier: "test1", invoiceStatus: "Import error2", invoiceCategory: "invoice with GR2", date: "22/01/2017", amount : 134527 },
{invoiceNumber: 1233, invoiceSupplier: "test2", invoiceStatus: "Import error1", invoiceCategory: "invoice with GR1", date: "22/01/2017", amount : 134527 },
{invoiceNumber: 1234, invoiceSupplier: "test3", invoiceStatus: "Import error3", invoiceCategory: "invoice with GR3", date: "22/01/2017", amount : 134527 },
];
//this.invoiceFilter.invoiceNumber = 1234;
//this.invoiceFilter.invoiceSupplier = "test2";
this.invoiceFilter.invoiceCategory = "invoice with GR2";
let filterdeInvoices = this.filterInvoices(this.invoiceList, this.invoiceFilter);
console.log(filterdeInvoices);
this.fieldToSortBy = "invoiceNumber";
let sortedInvoices = this.sortInvoices(filterdeInvoices, this.fieldToSortBy);
console.log(sortedInvoices);
}
invoiceFilter = new Invoice();
fieldToSortBy: string;
invoiceList: Invoice[];
filterInvoices(invoiceList:Invoice[], invoiceFilter: Invoice): Invoice[] {
return invoiceList.filter((invoice) => (invoiceFilter.invoiceNumber ? invoiceFilter.invoiceNumber === invoice.invoiceNumber : true) &&
(invoiceFilter.invoiceSupplier ? invoiceFilter.invoiceSupplier === invoice.invoiceSupplier : true) &&
(invoiceFilter.invoiceStatus ? invoiceFilter.invoiceStatus === invoice.invoiceStatus : true) &&
(invoiceFilter.invoiceCategory ? invoiceFilter.invoiceCategory === invoice.invoiceCategory : true));
}
sortInvoices(invoiceList:Invoice[], fieldToSortBy: string): Invoice[] {
return invoiceList.sort((inv1, inv2) => (inv1[fieldToSortBy] > inv2[fieldToSortBy] ? 1 : -1));
}
}
回答3:
I would recommend to use a Pipe
for filtering stuff like this.
Your Pipe
could look like this:
- check incoming variables
- filter your invoices
- order them if required
@Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
public transform(invoices: Invoice[], searchOptions: any): Invoice[] {
if (!invoices || !invoices.length) return [];
if (!searchOptions) return [];
let filtered = invoices.filter(i => {
return i &&
(!searchOptions.number || i.invoiceNumber.toString().indexOf(searchOptions.number) >= 0) &&
(!searchOptions.name || i.invoiceSupplier.toLowerCase().indexOf(searchOptions.name.toLowerCase()) >= 0) &&
(!searchOptions.status || i.invoiceStatus === searchOptions.status) &&
(!searchOptions.category || i.invoiceCategory === searchOptions.category);
});
let orderBy = searchOptions.orderBy;
if (!orderBy) return filtered;
/* credits for sorting goes to: 'Ankit Singh' ! :) */
return filtered.sort((a, b) => {
switch (orderBy) {
default: return 0;
case 'invoiceNumber':
case 'amount':
return a[orderBy] - b[orderBy];
case 'invoiceSupplier':
case 'invoiceStatus':
case 'invoiceCategory':
return (a[orderBy] == [a[orderBy], b[orderBy]].sort()[1] ? 1 : -1);
case 'date': {
const x = new Date(a.date.split('/').reverse().join('/'));
const y = new Date(b.date.split('/').reverse().join('/'));
return x.getTime() - y.getTime();
}
}
});
}
}
And use this Pipe
the following way:
<div class="row" *ngFor="let invoice of invoiceList | filter:searchOptions">
<div>{{ invoice.invoiceNumber }}</div>
<div>{{ invoice.invoiceSupplier }}</div>
<div>{{ invoice.date }}</div>
<div>{{ invoice.amount }}</div>
</div>
Those searchOptions
is an object coming from our form:
<md-input-container>
<input mdInput ngModel name="name" placeholder="Invoice supplier name">
</md-input-container>
<md-select placeholder="Invoice status" ngModel name="status">
<md-option *ngFor="let status of statusArray" [value]="status.val">
{{ status.name}}
</md-option>
</md-select>
<md-select placeholder="Invoice category" ngModel name="category">
<md-option *ngFor="let category of categoryArray" [value]="category.val">
{{ category.name}}
</md-option>
</md-select>
<md-select placeholder="order by" ngModel name="orderBy">
<md-option *ngFor="let key of invoiceKeyArray" [value]="key.val">
{{ key.name }}
</md-option>
</md-select>
<button md-raised-button color="primary" (click)="searchOptions = f.value">search</button>
<button md-raised-button color="accent" (click)="resetForm(f);">reset</button>
live demo: http://plnkr.co/edit/VPTnIOpieKt3YLqsEncr?p=preview
来源:https://stackoverflow.com/questions/41809812/how-to-do-a-global-search-in-angular-2