Reputation: 895
Based on a previous question of mine i am trying to build - with the help of the community - a search filter function that works even when the user types non Latin characters in the search input field (in this case Swedish letters).
This is what i have until now:
var langMap = {
'a' : 'å',
'a' : 'ä',
'o' : 'ö'
}
$('#search-items-box').keyup(function(){
var valThis = $(this).val().toLowerCase();
var filteredWord = valThis.split('').map(function(letter){
if (langMap[letter]) {
return langMap[letter];
}
return letter;
}).join('');
if(filteredWord == ""){
$('.itemsList .m3-item').show();
} else {
$('.itemsList .m3-item').each(function(){
var text = $(this).text().toLowerCase();
(text.indexOf(filteredWord) == 0) ? $(this).show() : $(this).hide();
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input placeholder="Search Me" id="search-items-box" type="text" />
<div class="itemsList">
<div class="m3-item">Orånge</div>
<div class="m3-item">Banäna</div>
<div class="m3-item">Potatö</div>
</div>
The problem is that the search doesn't work properly. If you try to type the three words you will notice that the results doesn't display.
Upvotes: 0
Views: 364
Reputation: 957
Here I propose a more data-centric approach. It is a question of normalizing your possible matches to your needs. According to your specification a normalized word should have the following characteristics:
This is done in the function normalizeWord
.
The rest of the code creates a dictionary
that binds the original
word to it's normalized representation. The filter
function returns
a list of the original words from your dataset, that are matched to the input.
Actually there is a little mismatch in binding the code to the DOM because this approach actually works on a given dataset. In real life I would just rebuild the HTML representation of the matches from the filtered list instead of showing and hiding already existing DOM elements.
$(function() {
var langMap = {
'å' : 'a',
'ä' : 'a',
'ö' : 'o'
};
var words = [
'Orånge',
'Banäna',
'Potatö'
];
// Create normalized words
// The map with the original and normalized word
var dictionary = {};
// Normalization
words.forEach(function(w) {
var word = normalizeWord(w);
dictionary[word] = w;
});
function normalizeWord(word) {
for (key in langMap) {
word = word.toLowerCase()
.replace(new RegExp(key, 'g'), langMap[key]);
}
return word;
}
function filter(word) {
var possibleMatch = normalizeWord(word);
var result = [];
for (normalizedWord in dictionary) {
if (normalizedWord.indexOf(possibleMatch) === 0) {
result.push(dictionary[normalizedWord]);
}
}
return result;
}
// Test
var results = [
'b -> ' + filter('b'),
'bs -> ' + filter('bs'),
'baNana -> ' + filter('baNana'),
'Potatö -> ' + filter('Potatö')
]
console.log(results);
// Binding to the DOM
$('#search-items-box').keyup(function() {
var value = $(this).val();
var matches = filter(value);
if (matches.length === 0) {
$('.itemsList .m3-item').show();
return;
}
$('.itemsList .m3-item').each(function() {
var $this = $(this),
value = $this.html();
if (matches.indexOf(value) > -1) {
$this.show();
} else {
$this.hide();
}
});
});
});
Upvotes: 0
Reputation: 109
The first condition is altering the character input at every key stroke if the condition is satisfied:
if (langMap[letter]) {
return langMap[letter];
Now, when you type in 'b', Banana appears in the search because 'b' is not part of your langMap array and hence, it is not modified. It searches for any word starting with 'b' and the search result is 'Banäna'
However, once you type 'a', Banana is no longer there because it was transformed into 'å'. As a result, it is searching for 'bå' which returns zero results (as expected).
On another note, you may also encounter another problem later on with your langMap array:
var langMap = {
'a' : 'å',
'a' : 'ä',
'o' : 'ö'
};
You have one key, 'a'
, which defines two different values. One of the values will never be accessible.
Based on our discussion, here is my proposed solution:
langMap
Transform the compared text into latin characters
var langMap = {
"å":"a",
"ä":"a",
"ö":"o"
}
$('#search-items-box').keyup(function(){
var valThis = $(this).val().toLowerCase();
var filteredWord = getLatinWord(valThis);
if(filteredWord == ""){
$('.itemsList .m3-item').show();
} else {
$('.itemsList .m3-item').each(function(){
var text = $(this).text().toLowerCase();
text = getLatinWord(text);
(text.indexOf(filteredWord) === 0) ? $(this).show() : $(this).hide();
});
}
});
function getLatinWord(word){
return word.split('').map(function(character){
if (langMap[character]) {
return langMap[character];
}
return character;
}).join('');
}
Upvotes: 1