Is there a way to ignore special characters in dropdown search?
So If I have a dropdown with the options Cantele, and Càntele, and I have Cà typed in the input box both options still show?
This unfortunately would add some heft to dropdown, as diacritic mapping is around 15kb (as can be seen in other libs).
https://github.com/select2/select2/blob/master/src/js/select2/diacritics.js#L4
I've considered adding it in the past, but am unaware of a reasonable solution.
[Edit] Perhaps there's some wisdom to be found here for a PR (Still 8kb)
You could, at least, allow us to specify a parameter like data-search-value so we can use a back-end languages or any other JavaScript function to remove accented characters from the value. And, of course, a way to pass the typed value through this function.
<option data-search-value="ciencia">Ciência</option>
$('.ui.dropdown')
.dropdown({
onInput: function(value) {
value.replace(/[(\u00C0-\u00C5)]/, 'A');
value.replace(/[(\u00C6-\u00CB)]/, 'E');
// …
// Somehow, update the value typed by the user
},
searchValue: 'data-search-value', // false = $(this).text() or something like that
});
Anyone came up with a workaround for this issue yet?
Here's my solution, mixing the select2 code with semantic:
semantic.js.zip
1) new dropdown option 'diac' for text and value:
else if (settings.fullTextSearch === 'diac' && module.diacSearch(searchTerm, text)) {
results.push(this);
return true;
}
2) new function 'stripDiacritics' based on select2 (see in doc attached)
3) new function 'diacSearch' based on 'exact' but with 'stripDiacritics'
diacSearch: function (query, term) {
query = module.stripDiacritics(query.toLowerCase());
term = module.stripDiacritics(term.toLowerCase());
if(term.indexOf(query) > -1) {
return true;
}
return false;
},
implementation proposal:
exactSearch: function (query, term) {
var diacriticsRegexByReplacement = {
'a' : /[âãäåāăą]/g,
'e' : /[èééêëēĕėęě]/g,
'i' : /[ìíîïìĩīĭ]/g,
'o' : /[óôõöōŏő]/g,
'u' : /[ùúûüũūŭů]/g,
'c' : /ç/g,
'n' : /ñ/g,
}
query = unaccent(query.toLowerCase());
term = unaccent(term.toLowerCase());
if(term.indexOf(query) > -1) {
return true;
}
return false;
function unaccent(str) {
for (var replacement in diacriticsRegexByReplacement) {
if (diacriticsRegexByReplacement.hasOwnProperty(replacement)) {
var diacriticRegex = diacriticsRegexByReplacement[replacement]
str = str.replace(diacriticRegex, replacement)
}
}
return str;
}
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 30 days if no further activity occurs. Thank you for your contributions.
I know I missed the action but what if we could just specify a custom filter function?
You would specify the function in the dropdown settings like
customFilter: (searchTerm, $choice, term) => true/false
This way the library won’t suffer weight gains due to diacritics specific data and anyone can adapt it to include any kind of missing filter. An example with diacritics can even be included in the docs.
It would work like the existing module.exactSearch and module.fuzzySearch.
As for the implementation, a few more lines to filterItems dropdown.js do the trick:
filterItems: function(query) {
var
searchTerm = (query !== undefined)
? query
: module.get.query(),
results = null,
escapedTerm = module.escape.string(searchTerm),
beginsWithRegExp = new RegExp('^' + escapedTerm, 'igm')
;
// avoid loop if we're matching nothing
if( module.has.query() ) {
results = [];
module.verbose('Searching for matching values', searchTerm);
$item
.each(function(){
var
$choice = $(this),
text,
value
;
if(settings.match == 'both' || settings.match == 'text') {
text = String(module.get.choiceText($choice, false));
if(settings.customFilter && settings.customFilter(searchTerm, $choice, text)) {
results.push(this);
return true;
}
if(text.search(beginsWithRegExp) !== -1) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
results.push(this);
return true;
}
}
if(settings.match == 'both' || settings.match == 'value') {
value = String(module.get.choiceValue($choice, text));
if(settings.customFilter && settings.customFilter(searchTerm, $choice, value)) {
results.push(this);
return true;
}
if(value.search(beginsWithRegExp) !== -1) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value)) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value)) {
results.push(this);
return true;
}
}
})
;
}
module.debug('Showing only matched items', searchTerm);
module.remove.filteredItem();
if(results) {
$item
.not(results)
.addClass(className.filtered)
;
}
},
You can then customize it however you want. Example with a custom accentFold function:
var accentMap = {
'á':'a', 'é':'e', 'í':'i','ó':'o','ú':'u'
};
var accentFold = function (s) {
if (!s) { return ''; }
var ret = '';
for (var i = 0; i < s.length; i++) {
ret += accentMap[s.charAt(i)] || s.charAt(i);
}
return ret;
};
$('.ui.dropdown').dropdown({
customFilter: function(searchTerm, $choice, text) {
query = accentFold(searchTerm.toLowerCase());
text = accentFold(text.toLowerCase());
if(text.indexOf(query) > -1) {
return true;
}
return false;
},
});
I'm still patching 2.3.1 creating a third fullTextSearch option 'diac'.
Similar to my May 2017 comment but now based on fuzzy search.
My new semantic.js is 744KB vs original 2.3.1 714KB.
semantic.js.zip
Hey guys, how about this approach:
https://thread.engineering/2018-08-29-searching-and-sorting-text-with-diacritical-marks-in-javascript/
is this easier/possible to implement?
Hey guys, how about this approach:
https://thread.engineering/2018-08-29-searching-and-sorting-text-with-diacritical-marks-in-javascript/
is this easier/possible to implement?
Thanks @brunotourinho. I've implemented this solution, worked for me!
In my case just needed to remove all diacritics, without any params or customizes, so I just added to semantic-ui.js the following:
add .normalize('NFD').replace(/[\u0300-\u036f]/g, ''); to text = String(module.get.choiceText($choice, false)) (Line 5191)
filterItems: function (query) {
var
searchTerm = (query !== undefined)
? query
: module.get.query(),
results = null,
escapedTerm = module.escape.string(searchTerm),
beginsWithRegExp = new RegExp('^' + escapedTerm, 'igm')
;
// avoid loop if we're matching nothing
if( module.has.query() ) {
results = [];
module.verbose('Searching for matching values', searchTerm);
$item
.each(function(){
var
$choice = $(this),
text,
value
;
if(settings.match == 'both' || settings.match == 'text') {
text = String(module.get.choiceText($choice, false)).normalize('NFD').replace(/[\u0300-\u036f]/g, '');
if(text.search(beginsWithRegExp) !== -1) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
results.push(this);
return true;
}
}
if(settings.match == 'both' || settings.match == 'value') {
value = String(module.get.choiceValue($choice, text));
if(value.search(beginsWithRegExp) !== -1) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, value)) {
results.push(this);
return true;
}
else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, value)) {
results.push(this);
return true;
}
}
})
;
}
module.debug('Showing only matched items', searchTerm);
module.remove.filteredItem();
if(results) {
$item
.not(results)
.addClass(className.filtered)
;
}
},
Hey guys, can we have @matheusrizzo1 implementation added to some release anytime soon?
Added option ignoreDiacritics to dropdown and search module for Fomantic-UI by https://github.com/fomantic/Fomantic-UI/pull/422 :grin:
See http://jsfiddle.net/t23uewyn/
Most helpful comment
Hey guys, how about this approach:
https://thread.engineering/2018-08-29-searching-and-sorting-text-with-diacritical-marks-in-javascript/is this easier/possible to implement?