solodynamo / ng2-search-filter

Angular 2 / Angular 4 / Angular 5 custom pipe npm module to make a search filter on any input, 🔥 1Million+ downloads
https://www.npmjs.com/package/ng2-search-filter
MIT License
149 stars 40 forks source link

Search on particular property #15

Open kharatps02 opened 7 years ago

kharatps02 commented 7 years ago

Hi,

I want to search on particular property of object instead of search on whole object.

solodynamo commented 7 years ago

hey , Acc to the example on readme , just put the values of that particular property of all objects in the items[] array thus filtering will happen based on its contents i.e the desired property.

kharatps02 commented 7 years ago

Thanks for quick reply. Actually I want to keep the other property e.g. place_id with search result for other operation but want to search on particular property e.g. place name.

solodynamo commented 7 years ago

Okay , you can always search on a particular field and you would get the whole object with it . After that use any property of that object you require.

kharatps02 commented 7 years ago

Like like, I didn't specify requirement correctly.

How to pass single property to search? . In following example i want to search only on name property. If i search 11 as search string then it shouldn't show anything, currently It searching on all properties of object that why getting ABC into search result. e.g. let items= [{_id:'11', name: "ABC" }, {_id:'12', name: "PQA" }, { _id:'13', name: "XYZ" }];

M1kemay commented 7 years ago

I'd like to ask this too. I have lengthy models with lots of misc and meta fields, is it possible to filter a list by only one of those fields?

Alternatively, is it possible to display only the field that is being matched? i.e. if search "123 fake st" result would be {{id}}{{name}} (<-- shows every time) {{address}} (<-- matched field) instead of everything (about 20 more fields)

Edit: Thanks for making this by the way, great work.

solodynamo commented 7 years ago

I would love to accept a PR providing this functionality.

apa-narola commented 6 years ago

I am facing same issue ! Can anyone tell me if i want to search based on multiple fields instead of only one. can i do so ?

I want to bind multiple search term to multiple fields of dataset.

For example, my dataset is like this,

items : any = [{ id:1, first_name : "ashish", middle_name : "B", last_name : "narola", industry : "Information & technology", country : "india", state : "gujarat", investment : 50000, ROI:10 // its percentage i.e. 10% }, { id:2, first_name : "usman", middle_name : "", last_name : "shaikh", industry : "Finance", country : "india", state : "maharashtra", investment : 40000, ROI:7 // its percentage i.e. 7% }, { id:3, first_name : "indrajit", middle_name : "", last_name : "kaplatiya", industry : "Stock Market", country : "india", state : "gujarat", investment : 90000, ROI:11 // its percentage i.e. 11% } ];

I have different filters like this,

  1. Name - with textbox // user can enter part of full name here
  2. Industry - its dropdown // user can select industry from dropdown to be search for specific industry
  3. Country - its dropdwon // user can select country from dropdown to be search for specific country
  4. ROI - its textbox number input // where user can input number of percentage so search percentage of ROI greater than that and so on.

Can anyone tell me how can i achieve this ?

Thanks in advance ! Ashish B. Narola

aVolpe commented 6 years ago

@apa-narola I am facing a similar issue, currently ng2-search-filter doesn't support filtering for a specific property, so I made a custom pipe like this:

    transform(values: any[], filterMap: any, numberToShow: number) {
        if (!values) return values;
        if (!filterMap) return values;

        return values.filter(value => {
            return this._filter(value, filterMap, numberToShow);
        });
    }

    _filter(item: any, filterMap: any, numberToShow: number) {
        let cont = 0;
        for (let property in filterMap) {
            if (!item.hasOwnProperty(property)) {
                continue;
            }
            if (!item[property]) {
                continue;
            }
            if (filterMap[property] === '*') {
                cont++;
                continue;
            }
            if (item[property].toString().toLowerCase().includes(filterMap[property].toLowerCase())) {
                cont++;
                continue;
            }
        }
        return cont === numberToShow;
    }

This receive a map like this:

{
    "property": "filterValue"
}

And

  {{ array | filter:filterObj:3 }}

This is not the ideal case, but works for me because I need a "and" between all properties, if you need an "or", you can change the _filter function to return true instead of add one to count.

apa-narola commented 6 years ago

@aVolpe Thank you very much for your reply to the comment, I shall try the way which you had suggested.

alindberg commented 6 years ago

Might I suggest the following changes to add this functionality. In adding a third optional string variable that defines the object's field to use as a compare. The following change checks for a null or undefined 3rd parameter. If so, just do as normal. If not, then just return the value of

12a13
>        * @param objectFieldName (optional)
14c15
<   transform(items: any, term: string): any {
---
>       transform(items: any, term: string, objectFieldName: string): any {
17c18
<     return Ng2SearchPipe.filter(items, term);
---
>               return Ng2SearchPipe.filter(items, term, objectFieldName);
24c25
<    *
---
>        * @param objectFieldName
26c27
<   static filter(items: Array<{ [key: string]: any }>, term: string): Array<{ [key: string]: any }> {
---
>       static filter(items: Array<{ [ key: string ]: any }>, term: string, objectFieldName: string): Array<{ [ key: string ]: any }> {
29a31
>               if ( objectFieldName === null || objectFieldName === undefined ) { // Object Field not defined so loop over object
40c42,46
<     });
---
>                       })
>               }
>               return items.filter( function(item:any) {
>                       return (item[objectFieldName].toString().toLowerCase().includes(toCompare)) ;
>               })
42a49
> 
alindberg commented 6 years ago

Here is the entire typescript source. I created a filter module and used this successfully with and without the field name. Note - If you use a field name, it must be a string or a string variable.

import { Pipe, PipeTransform, Injectable } from '@angular/core';
@Pipe({
    name: 'filter',
    pure: false
})
@Injectable()
export class MySearchPipe implements PipeTransform {
    /*
     * @param items object from array
     * @param term term's search
     * @param objectFieldName (optional)
     */
    transform(items: any, term: string, objectFieldName: string): any {
        if ( !term || !items ) return items;
        return MySearchPipe.filter(items, term, objectFieldName);
    }
    /*
     * @param items List of items to filter
     * @param term  a string term to compare with every property of the list
     * @param objectFieldName
     */
    static filter(items: Array<{ [ key: string ]: any }>, term: string, objectFieldName: string): Array<{ [ key: string ]: any }> {
        const toCompare = term.toLowerCase();
        if ( objectFieldName === null || objectFieldName === undefined ) { // Object Field not defined so loop over object
            return items.filter(function (item: any) {
                for ( let property in item ) {
                    if ( item[ property ] === null || item[ property ] == undefined ) {
                        continue;
                    }
                    if ( item[ property ].toString().toLowerCase().includes(toCompare) ) {
                        return true;
                    }
                }
                return false;
            })
        }
        return items.filter( function(item:any) {
            return (item[objectFieldName].toString().toLowerCase().includes(toCompare)) ;
        })
    }
}

Example use in your template. (Note class and style information has been removed)

<table>
    <thead>
    <tr>
        <th>
            <label for="allItems">Product</label>
            <input id="allItems" type="text" placeholder="Search" [(ngModel)]="searchProduct"/>
        </th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let productItem of productInfo |filter:searchProduct:'plName'">
        <td>{{productItem.plName}}</td>
    </tr>
    </tbody>
</table>
dhruvaprajapati commented 4 years ago

Like like, I didn't specify requirement correctly.

How to pass single property to search? . In following example i want to search only on name property. If i search 11 as search string then it shouldn't show anything, currently It searching on all properties of object that why getting ABC into search result. e.g. let items= [{_id:'11', name: "ABC" }, {_id:'12', name: "PQA" }, { _id:'13', name: "XYZ" }];

Did you got a fix for this ?