Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
967 views
in Technique[技术] by (71.8m points)

angular - Trying to filter data in *ngFor directive

I'm trying to filter my array data on a table from Angular with the package w-ng5, but it's searching and it doesn't find nothing (blank list). This is the steps that I've followed:

package npm

Here you can find the documentation of w-ng5 for Angular.

Steps

Install the package with npm

npm install w-ng5 --save

Import in the module of my aplication

//Pipes of the aplication
import { TruncatePipe } from './pipes/truncate.pipe';
import { PipesModule } from 'w-ng5';

Declare section of app.module

imports: [
    BrowserModule,
    RouterModule.forRoot(routes),
    FormsModule,
    NgbModule.forRoot(),
    HttpClientModule,
    ColorPickerModule,
    PdfViewerModule,
    CurrencyMaskModule,
????ReactiveFormsModule,
    NgxPaginationModule,
    NgxTypeaheadModule,
    PipesModule
  ],

And the implementation:

<input type="text" [(ngModel)]="filterInvoice" name="filterInvoice">
<table class="table table-hover table-sm">
  <caption>Tabla de Facturas</caption>
  <thead class="thead-dark">
    <tr>
      <th class="text-center">#</th>
      <th class="text-center">Invoice</th>
      <th class="text-center">Note</th>
      <th class="text-center">State</th>
      <th class="text-center">Customer</th>
      <th class="text-center">Date</th>
      <th class="text-center">Days</th>
      <th class="text-center">Expiration</th>
      <th class="text-center">Payment Type</th>
      <th class="text-center">Option</th>
     </tr>
   </thead>
   <tbody>
     <tr *ngFor="let invoice of invoices | filter : filterInvoice | paginate: { itemsPerPage: 10, currentPage: page }, index as i">
       <td class="text-center">
          {{i+1}}
       </td>
       <td class="text-center">
          {{invoice.number_invoice}}
       </td>
       <td class="text-center">
          {{invoice.note_invoice}}
       </td>
       <td class="text-center">
          {{invoice.state_invoice}}
       </td>
       <td class="text-center">
          {{invoice.customer_invoice}}
       </td>
       <td class="text-center">
          {{invoice.date_invoice}}
       </td>
       <td class="text-center">
          {{invoice.days_invoice}}
       </td>
       <td class="text-center">
          {{invoice.expiration_invoice}}
       </td>
       <td class="text-center">
          {{invoice.payment_invoice}}
       </td>
       <td class="text-center">
          <button type="button" class="btn btn-warning btn-sm">
             Detail
          </button>
       </td>
     </tr>         
   </tbody>        
</table>

Data table JSON

invoices:any[] =[
    {
      number_invoice: '996',
      note_invoice: '0001',
      state_invoice: 'pending',
      customer_invoice: 'Johan Corrales',
      date_invoice: '2018-10-30',
      days_invoice: '30',
      expiration_invoice: '2018-11-30',
      payment_invoice: 'Credit'
    },
    {
      number_invoice: '997',
      note_invoice: 'N/A',
      state_invoice: 'Pay out',
      customer_invoice: 'Richard Castle',
      date_invoice: '2018-10-30',
      days_invoice: '0',
      expiration_invoice: 'N/A',
      payment_invoice: 'Credit'
    },
    {
      number_invoice: '998',
      note_invoice: 'N/A',
      state_invoice: 'pending',
      customer_invoice: 'Kyara Wolff',
      date_invoice: '2018-10-30',
      days_invoice: '30',
      expiration_invoice: '2018-11-30',
      payment_invoice: 'Credit'
    },
    {
      number_invoice: '999',
      note_invoice: 'N/A',
      state_invoice: 'pending',
      customer_invoice: 'Donaldo Trumpete',
      date_invoice: '2018-10-30',
      days_invoice: '30',
      expiration_invoice: '2018-11-30',
      payment_invoice: 'Credit'
    },
    {
      number_invoice: '1000',
      note_invoice: '0001',
      state_invoice: 'pending',
      customer_invoice: 'Mark Wahlber',
      date_invoice: '2018-10-30',
      days_invoice: '30',
      expiration_invoice: '2018-11-30',
      payment_invoice: 'Cash'
    },
    {
      number_invoice: '1001',
      note_invoice: 'N/A',
      state_invoice: 'Pay out',
      customer_invoice: 'Ryan Reynolds',
      date_invoice: '2018-10-30',
      days_invoice: '0',
      expiration_invoice: 'N/A',
      payment_invoice: 'Cash'
    },
  ]

Service Invoice

  public getInvoice()
  {
    return new Promise(
      resolve=>{
        this.http.get('authentication/consultInvoice')
        .subscribe(
        data => resolve(data)
        )
      }
    )
  };

Constructor Component

constructor(private _serviceInvoice:InvoiceService)
  {    
    _serviceInvoice.getInvoice()
    .then(data=>{
      this.invoices = data;
      this.onFilterChange();
    })
    .catch(err=>{
      console.log(err);
    });
  };

And this is the error that I'm getting from Angular> ERROR TypeError: "item is null; can't access its "toString" property"

Notes I know about this(docs from Angular):

Filtering and especially sorting are expensive operations. The user experience can degrade severely for even moderate-sized lists when Angular calls these pipe methods many times per second

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can create a filter function that is called whenever your filter string changes.

The code will look something like this:

  isMatch(item) {
    if (item instanceof Object) {
      return Object.keys(item).some((k) => this.isMatch(item[k]));
    } else {
      return item.toString().indexOf(this.filterString) > -1
    }
  }

This will iterate through the object recursively, and look for any matches. While it's not necessary (seeing as your object structure is flat), it could be useful if your structure ever changes. Bear in mind it's case sensitive as it stands

You then need to create a function that calls it, like so:

onFilterChange() {
  this.filtered = this.invoices.filter((invoice) => this.isMatch(invoice));
}

And amend your input so that it refilters any time that the search string is changed

<input [(ngModel)]="filterString" (ngModelChange)="onFilterChange()" />

Here is a Stackblitz demo


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...