Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Search on particular property #15

Open
kharatps02 opened this issue Aug 29, 2017 · 12 comments
Open

Search on particular property #15

kharatps02 opened this issue Aug 29, 2017 · 12 comments

Comments

@kharatps02
Copy link

Hi,

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

@solodynamo
Copy link
Owner

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
Copy link
Author

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
Copy link
Owner

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
Copy link
Author

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
Copy link

M1kemay commented Sep 28, 2017

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
Copy link
Owner

I would love to accept a PR providing this functionality.

@apa-narola
Copy link

apa-narola commented Jan 11, 2018

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
Copy link
Collaborator

aVolpe commented Jan 11, 2018

@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
Copy link

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

@alindberg
Copy link

alindberg commented Jul 16, 2018

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
Copy link

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
Copy link

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 ?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants