I've got a list of countries in JSON format like so:
{
'name': 'United States',
'number': '+1',
'abbr': 'US'
},
{
'name': 'United Kingdom',
'number': '+44',
'abbr': 'GB'
},
{
'name': 'Japan',
'number': '+81',
'abbr': 'JP'
},
...
At the moment I'm using power-select to allow the user to search by either the number or name properties by using the matcher option. My matcher code is:
let concatenatedFields = get(country, 'name') + get(country, 'number');
let lowerCasedFields = (concatenatedFields).toLowerCase();
return (concatenatedFields + lowerCasedFields).indexOf(term);
I need to concatenate a lower case version of the fields onto the matcher because if I don't then the matcher is taken literally and I only get exact matches. For example united states would not trigger a match for United States, which is annoying.
Basically, __I want to be able to make use of the power-select's fuzzy matching with the matcher attribute that you get when you use the searchField option__, and I feel like this is how it should work out of the box.
This would mean that my matcher code just be:
let concatenatedFields = get(country, 'name') + get(country, 'number');
return (concatenatedFields).indexOf(term);
and I'd get all of the fuzzy matching options like fuzzy case matching as well as all the other great fuzzy matching features power-select has!
I'm not sure if this is already possible somehow. If it is I apologise.
I think another good way of achieving this behaviour would be to enable you to pass an array of the fields that you want to search by into the searchField attribute or create a searchFields option that would take multiple fields as described.
You can. I made the default matches function an exported util: https://github.com/cibernox/ember-power-select/blob/master/addon/utils/group-utils.js#L970
It doesn't use fuzzy matching, but it normalizes diacritics like 谩脿酶莽膲 and such. If you invoke it with defaultMatcher(concatenatedFields, searchTerm) you will get the default behaviour searching on both fields. But it's not fuzzy.
I'm going to close this, but feel free to repopen if it doesn't solve your problem.
@cibernox
Do you have planned to implement an macher for many properties? Like passing a list to searchFields?
This is how we could avoid writing many custom matchers
@BennyAlex I don't think it would be wise as there is a lot of possible strategies.
Imagine you have first_name and last_name. If the user types jo it will find "John Williams" but also "Scarlet Johanson". So far so good. But what about n a.
Should it find "Anton Allaire" or "Akira Ronin" (because properties can be concatenated as "Ronin Akira")? Or both? The space is meaninful or should "Navidad" also match?
I gave it some thought and I think that it will be better to let people do their own matchers.
To avoid repetition you can extract your matchers to util helpers that you just import.
import { matchNameAndSurname } from 'my-app/utils/custom-matchers';
export default Component.extend({
matchNameAndSurname
});
{{#power-select ... matcher=matchNameAndSurname}}
If you want to skip the javascript file, a helper to generate matchers is also extremely simple:
{{#power-select ... matcher=(match-by "firstName" "lastName")}}
export default Helper.helper(function(fields, { separator = ' ' } = {}) {
return function(item, term) {
let concatenation = fields.map((f) => get(item, f)).join(separator);
return concatenation.indexOf(term);
}
});
@cibernox
okay I see your point, but you could give the matcher (optional) parameters (for example ignore spaces, then 'n a' would only match 'Navidad') and let the user decide how the matcher should work.
I think in many cases this would be enought and I dont need a custom matcher.
When I am trying to use the defaultMatcher in my own matcher I get an error.
Do I import it correctly (import defaultMatcher from "ember-power-select/utils/group-utils";)?
Can you provide me an example how to use your 'match-by' helper in combination with defaultMatcher, please?
@BennyAlex You're almost there. It's a named export. import { defaultMatcher } from 'ember-power-select/utils/group-utils'; should work.
Using the default matcher would be just import it and use it to compare passing the concatenated fields. It will take care of stripping diacritics and ignoring capitalisation. Although the stripDiacritics is also an independent function you can import if you want.
import { defaultMatcher } from 'ember-power-select/utils/group-utils';
export default Helper.helper(function(fields, { separator = ' ' } = {}) {
return function(item, term) {
let concatenation = fields.map((f) => get(item, f)).join(separator);
return defaultMatcher(concatenation, term);
}
});
Most helpful comment
@BennyAlex I don't think it would be wise as there is a lot of possible strategies.
Imagine you have
first_nameandlast_name. If the user typesjoit will find "John Williams" but also "Scarlet Johanson". So far so good. But what aboutn a.Should it find "Anton Allaire" or "Akira Ronin" (because properties can be concatenated as "Ronin Akira")? Or both? The space is meaninful or should "Navidad" also match?
I gave it some thought and I think that it will be better to let people do their own matchers.
To avoid repetition you can extract your matchers to util helpers that you just import.
If you want to skip the javascript file, a helper to generate matchers is also extremely simple: