Explanation. I am new to VueJS and JavaScript and I am trying to setup a search bar. So far, it works well, but I have one issue with it. I would like to be able to search through a description of an object even if the words I typed in the search bar are not in the correct order.
Example.
The string in the description would be "Gucci blue belt". If I type "Gucci blue", the result shows up since the description contains those words in this exact order. Therefore, I would like to add the functionality for which I can type "Gucci belt" and the item with the description "Gucci blue belt" would show up.
My current code in the computed section in VueJS
filteredsortedobjects (){
return this.sortedobjects.filter(object => {
var Objectslist_n = object.name;
var Objectslist_q = object.quantity;
var Objectslist_c = object.category;
var Objectslist_s = object.section;
var Objectslist_d = object.description;
var Objectslist_date = object.reception_date;
var Input = this.searchQuery;
/* Form arrays with all the information in the table */
var Objectslist_nq = Objectslist_n.concat(Objectslist_q);
var Objectslist_nqc = Objectslist_nq.concat(Objectslist_c);
var Objectslist_nqcs = Objectslist_nqc.concat(Objectslist_s);
var Objectslist_nqcsd = Objectslist_nqcs.concat(Objectslist_d);
var Objectslist_nqcsddate = Objectslist_nqcsd.concat(Objectslist_date);
/* Filtered variables */
var F_Objectslist = RemoveAccents(Objectslist_nqcsddate.toLowerCase());
var F_Input = RemoveAccents(this.searchQuery.toLowerCase());
/* Function to remove accents */
function RemoveAccents(str) {
var accents = 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÕÖØòóôõöøÈÉÊËèéêëðÇçÐÌÍÎÏìíîïÙÚÛÜùúûüÑñŠšŸÿýŽž';
var accentsOut = "AAAAAAaaaaaaOOOOOOOooooooEEEEeeeeeCcDIIIIiiiiUUUUuuuuNnSsYyyZz";
str = str.split('');
var strLen = str.length;
var i, x;
for (i = 0; i < strLen; i++) {
if ((x = accents.indexOf(str[i])) != -1) {
str[i] = accentsOut[x];
}
}
return str.join('');
};
console.log(F_Objectslist);
console.log(F_Input);
return F_Objectslist.includes(F_Input)
})
}
I am aware that the function to remove accents is not yet used since I have been testing things.
What I have tried doing. I have tried setting the variable F_Input (what is being written in the search bar) and F_Objectslist (a variable containing an array with all the words for the items, for instance, the names, the category, the section, the quantity, a description and a date) as strings by array.split(" "). That way, I was able to have an array of strings in this format in the console ["word", "word2", ...] for both my variables.
From this point, I am unsure on how to check if the strings in my F_Input array are all present in the array for F_Objectslist even if they are in a different order.
Thank you so much for your time!
Split F_Input on " ", then you can use 'Array.prototype.map()' to loop through the F_Input array of search terms using the same technique you have now.
Notice that I've chained all these together with a final call to the .every() method. That last one says that every map operation (search) must result in a true (or the result of the map operation must result in an array full of nothing but true);
const F_Objectslist = "this is search term, and this is term search".split(' ');
const F_Input = "search term";
let result = search(F_Objectslist, F_Input);
console.log(result);
let notFoundResult = search(F_Objectslist, "search dog");
console.log(notFoundResult);
function search(text, terms) {
return terms.split(' ').map(term =>text.includes(term)).every(found=>found===true);
}
I think you were already pretty close, I would approach it like this
function searchString(input, match) {
let is_a_match = true;
const match_arr = match.split(' ');
const input_arr = input.split(' ');
input_arr.forEach(word => {
if (match_arr.indexOf(word) === -1) {
is_a_match = false;
}
});
return is_a_match;
}
A working fiddle can be found here
Here is my answer.
I managed to make a quite responsive search bar that seeks information in the array! Here is the code if anyone is curious about it!
page.vue inside computed
filteredsortedobjects (){
return this.sortedobjects.filter(object => {
var Objectslist_n = "a" + object.name;
var Objectslist_c = object.category;
var Objectslist_s = object.section;
var Objectslist_q = object.quantity;
var Objectslist_d = object.description;
var Objectslist_date = object.reception_date;
var Input = this.searchQuery;
/* Form arrays with all the information in the table */
var Objectslist_nc = Objectslist_n + " " + Objectslist_c;
var Objectslist_ncs = Objectslist_nc + " " + Objectslist_s;
var Objectslist_ncsq = Objectslist_ncs + " " + Objectslist_q;
var Objectslist_ncsqd = Objectslist_ncsq + " " + Objectslist_d;
var Objectslist_ncsqddate = Objectslist_ncsqd + " " + Objectslist_date;
/* Filtered variables */
var F_Objectslist = RemoveAccents(Objectslist_ncsqddate.toLowerCase()).split(" ") + " ";
var F_Input = RemoveAccents(this.searchQuery.toLowerCase()).split(" ");
/* Function to remove accents */
function RemoveAccents(str) {
var accents = 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÕÖØòóôõöøÈÉÊËèéêëðÇçÐÌÍÎÏìíîïÙÚÛÜùúûüÑñŠšŸÿýŽž';
var accentsOut = "AAAAAAaaaaaaOOOOOOOooooooEEEEeeeeeCcDIIIIiiiiUUUUuuuuNnSsYyyZz";
str = str.split('');
var strLen = str.length;
var i, x;
for (i = 0; i < strLen; i++) {
if ((x = accents.indexOf(str[i])) != -1) {
str[i] = accentsOut[x];
}
}
return str.join('');
};
return F_Input.every(object => {
if (F_Objectslist.indexOf(object) === -1) {
}
else {
return F_Objectslist.indexOf(object)
}
})
})
}
I have an input with a v-model="searchQuery" attribute. Also, there is a table containing
<tr id="tr" v-for="object in filteredsortedobjects" v-bind:key="object.name">
<td>
<p>{{ object.name }}</p>
</td>
<td>
<p>{{ object.category }}</p>
</td>
<td>
<p>{{ object.section }}</p>
</td>
<td>
<p>{{ object.quantity }}</p>
</td>
<td>
<p>{{ object.description }}</p>
</td>
<td>
<p>{{ object.reception_date }}</p>
</td>
</tr>
The object.something are imported from a JSON file using
<script>
import objects from "./Database/Objects.json";
</script>
You would probably have to set some data information in the data() section
searchQuery: ""
Related
I have a localStorage object like this:
Key: jpxun
Value: [{"id":"0","name":"royal"},{"id":"1","name":"tippins"},{"id":"4","name":"leviosa"},{"id":"5","name":"vicious"}]
I have this JS to display output the localStorage:
var jpxun = JSON.parse(localStorage.getItem('jpxun')) || [];
if (jpxun) {
var jpxun_length = jpxun.length;
} else {
var jpxun_length = 0;
}
var hst = document.getElementById("usernames");
var MyUsernames = JSON.parse(localStorage.getItem("jpxun"));
if (jpxun_length > 0) {
// declare array to hold items for outputting later in plain text format
var plain_text_array = [];
for (var i = 0; i < MyUsernames.length; i++) {
var un1 = MyUsernames[i].name;
hst.innerHTML += "<li>" +"<a id="+MyUsernames[i].id + " href='#content' onclick='deleteById(this)'>x </a>" + un1 + "</li>";
// add word to plain text array
plain_text_array.push(un1);
}
}
Each element is outputted in a list item with an 'x' as a hyperlink so that it can be clicked and that element is deleted from localStorage.
This is the code to delete the item from localStorage:
var deleteById = function ( self ){
MyUsernames = MyUsernames.filter(function(elem) {
return elem.id !== self.id;
});
localStorage.setItem("jpxun",JSON.stringify(MyUsernames));
self.parentNode.parentNode.removeChild(self.parentNode);
}
That works fine.
Unfortunately I don't really understand how the code works in deleteById.
As that is the case, I am stuck on working out how to delete the corresponding record from plain_text_array when its value is deleted from localStorage.
I would try to find the text in the array thats includes that string 'id="item_id"':
plain_text_array = plain_text_array.filter(item => !item.includes(`id="${self.id}"`));
Just add it in the end of deleteById function.
I am making an html page which is a typer of a foreign script.
my progress: HERE
Here's the entire javascript:
function getReplacedText(latinText) {
if (!latinText) {
return "";
}
var replacedText = "";
for (var i = 0, len = latinText.length; i < len; i++) {
var curLetter = latinText[i];
var pos1Txt = latinText[i + 1];
var pos2Txt = latinText[i + 2];
if (!(curLetter == "")) {
var dualLetter = latreplaced[curLetter + pos1Txt];
if (dualLetter) {
replacedText += dualLetter;
i++;
continue;
}
}
replacedText += latreplaced[curLetter] || curLetter;
}
return replacedText;
}
var latreplaced = {
"u":"う",
"ku":"く",
"tsu":"つ",
};
function onLatinTextChange(txt) {
var replacedTextareaElem = document.getElementById("replaced_textarea");
var div = document.createElement("div");
var replacedHtmlEntities = getReplacedText(txt);
div.innerHTML = replacedHtmlEntities;
replacedTextareaElem.value = div.innerText;
}
The purpose of this project is to create a virtual phonetic keyboard to type certain forign scripts by only using Latin alphabets, without its keyboard setting installed.
Basically, if you enter an alphabet into the input <textarea>, it renders its corresponding foreign alphabet. (For instance, input 'u' > output 'う', input 'ku' > output 'く')
Here is my problem: So far I have enabled rendering an output when one or two alphabet is typed into the input box. But I cannot figure out how to enable the same by entering three alphabets. (For instance, input 'tsu' > output 'つ')
"u":"う", // <- can convert
"ku":"く", // <- can convert
"tsu":"つ", // <- cannot convert!
In the javascript code, there is a var called dualLetter, which goes by the following script:
var dualLetter = latreplaced[curLetter + pos1Txt];
How can I edit this part of code (or the entire javascript) to be able to convert 3 or more input alphabets? Do I need to make var tripleLetter, or create a whole new system? Any alternative ways would also be helpful.
[edit] a solution inspired by your code :
I changed the main function but this definitively works
live demo : https://jsfiddle.net/alias_gui3/wds426mq/12/
source code :
var dictionnary = {
"u":"う",
"ku":"く",
"tsu":"つ",
"test for spaces": "😍"
};
var maxLength = Object.keys(dictionnary)
.reduce((a, b) => a.length > b.length ? a : b) // get the longest word
.length; // and it's length
function translate (text) {
var translated = "";
var cur = 0;
while (cur < text.length) {
var testedPhoneme;
var symbol = undefined;
for (var length = maxLength; length > 0; length --) {
testedPhoneme = text.substr(cur, length);
if (dictionnary[testedPhoneme]) {
symbol = dictionnary[testedPhoneme];
break; // stop the loop
}
}
if (symbol) {
translated += symbol;
cur += testedPhoneme.length;
}
else {
translated += text[cur]
cur++;
}
}
return translated
}
function onLatinTextChange(txt) {
var replacedTextareaElem = document.getElementById("replaced_textarea");
var div = document.createElement("div");
var replacedHtmlEntities = translate(txt);
div.innerHTML = replacedHtmlEntities;
replacedTextareaElem.value = div.innerText;
}
[previous post] a simple solution :
I suggest you split your text using spaces
If i understand well, you want to type u ku tsu to get うくつ, not ukutsu, if this is right then something like that could work :
const dictionnary = {
"u": "う",
"ku": "く",
"tsu": "つ"
var phonemes = text.split(' ') // split text by spaces
var translatedArray = phonemes.map(function (phoneme) {
return dictionnary[phoneme] || phoneme
// will return the latin phoneme if it is not in the dictionnary
})
translatedString = translatedArray.join('')
On this question here I finally succeed to change two values from the same column - priority. I tried to do it on select list - column priority lov - but with no conclusive success. Selects don't have "default values" properties like text fields, so I tried to get it from the source.context.index properties. Here the oracle apex app, user and password test.
I'm considering to use pure Javascript, to deal with it.
The Javascript is triggered after change the select list:
var source = apex.jQuery(this.triggeringElement).find('select[name="f31"]')
console.log(source)
var lista = apex.jQuery(source.context.form).find('select[name="f31"]')
console.log(lista)
console.log('source.context.selectedIndex inicial ' +source.context.index)
var valor_default = lista[0].selectedIndex
console.log(valor_default)
var index_default = apex.jQuery(this.triggeringElement).closest('select[name="f31"]').find('option[selected]')[0].index
console.log('indice default:' + index_default)
for (var x=0;x<lista.length;x++){
if (source.context.selectedIndex == lista[x].selectedIndex && source.context != lista[x]){
console.log('selectedIndex ' + source.context.selectedIndex)
console.log('source.context')
console.log(source.context)
console.log('lista[x]')
console.log(lista[x])
lista[x].selectedIndex = index_default
index_default = source.context.selectedIndex
// lista[x].defaultValue = source.context.defaultValue
// source.context.defaultValue = source.context.value
}
}
Fellows,
A possible solution was found.
On form properties - footer text, an array is build to get the indexes of object f31 - select list:
<script >
var listaOriginal = document.getElementsByName('f31')
var valordefault = []
for (item of listaOriginal) {
valordefault.push(item.selectedIndex)
}
console.log(valordefault)
</script>
on change from select list the array is used to compare with the changes:
var source = apex.jQuery(this.triggeringElement).find('select[name="f31"]')
var lista = apex.jQuery(source.context.form).find('select[name="f31"]')
var valueDefault = lista[0].selectedIndex
var happyIndex = ''
for (var happy=0;happy<lista.length; happy++){
if (source.context === lista[happy]){
happyIndex = happy
}
}
for (var x=0;x<lista.length;x++){
if (source.context !== lista[x] && source.context.selectedIndex == lista[x].selectedIndex){
var my_table = {};
my_table.source_context_selectedIndex = source.context.selectedIndex
my_table.lista_x_selectedIndex = lista[x].selectedIndex
my_table.valueDefault = valueDefault[x]
console.table(tabela)
lista[x].selectedIndex = valueDefault[happyIndex]
valueDefault[happyIndex] = valueDefault[x]
valueDefault[x]=lista[x].selectedIndex
// source.context.defaultValue = source.context.value
}
console.log(valueDefault)
}
Im giving my users the possibility to filter products without refreshing the page with ajax. i update the url to make it look like :
http://mywebsite.com/products/filter?style=7-1-2&price=4-5-7&brand=48-12-5&color=8-4
where the int values are id's split by -.
so i have the options:
style
price
brand
color
what i want is get these values in a var for each filter option so that i end with :
var styleValues = 7,1,2
var priceValues = 4,5,7
if only price filter is selected the url will look like
http://mywebsite.com/products/filter?price=4-5-7
so i cant split on the tags for the filters.
I really like to know what would be the best way to turn the url to different vars.
What i already know :
how to get the filter part:
var filterPart =window.location.search;
Great article on css tricks covering just this:
http://css-tricks.com/snippets/javascript/get-url-and-url-parts-in-javascript/
JavaScript can access the current URL in parts. For this URL:
http://css-tricks.com/example/index.html
window.location.protocol = "http:"
window.location.host = "css-tricks.com"
window.location.pathname = "example/index.html"
So to get the full URL path in JavaScript:
var newURL = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname;
If you need to breath up the pathname, for example a URL like http://css-tricks.com/blah/blah/blah/index.html, you can split the string on "/" characters
var pathArray = window.location.pathname.split( '/' );
Then access the different parts by the parts of the array, like
var secondLevelLocation = pathArray[0];
To put that pathname back together, you can stitch together the array and put the "/"'s back in:
var newPathname = "";
for (i = 0; i < pathArray.length; i++) {
newPathname += "/";
newPathname += pathArray[i];
}
Or like this::
http://css-tricks.com/snippets/javascript/get-url-variables/
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
maybe this can help you :
var Request = {
QueryString : function (item) {
var svalue = location.search.match(new RegExp("[\?\&]" + item + "=([^\&]*)(\&?)","i"));
return svalue?svalue[1]:svalue;
},
queryAllString : function() {
var urlLocation = location.href;
var startPosition = urlLocation.indexOf("?");
if (startPosition < 0) {
return '';
} else {
return urlLocation.slice(startPosition);
}
}
}
If you want to get price,you can do like this:
Request.QueryString("price")
My own take on this problem would be:
// this is simply to compensate for the lack of a current document.location to search:
var documentURL = 'http://mywebsite.com/products/filter?style=7-1-2&price=4-5-7&brand=48-12-5&color=8-4',
tempA = document.createElement('a');
tempA.href = documentURL
var searches = {
'get': function() {
var queries = {
// a cache of all named parameters found:
'found': []
},
// stripping off the leading '?':
queryString = tempA.search.substring(1),
// getting the key-value pairs:
keyValues = queryString.split('&'),
// to be used withi the forEach():
pair;
keyValues.forEach(function(el) {
// creating an array consisting of the keyName and keyValue:
pair = el.split('=');
// if we have both a name and a value we proceed:
if (pair.length === 2) {
if (!queries[pair[0]]) {
// if there is no present entry for the current key, we:
// push the key to the 'found' array, and
// create a record in the queries object for that key
// containing an array of the found values:
queries.found.push(pair[0]);
queries[pair[0]] = pair[1].split('-');
} else {
// otherwise (there is an existing key in the queries object),
// we push the values to the end of the existing array:
queries[pair[0]].push(pair[1])
}
}
});
return queries;
}
};
var cachedSearches = searches.get(),
allKeys = cachedSearches.found;
allKeys.forEach(function(el){
console.log(el, cachedSearches[el], cachedSearches[el].join(', '));
});
References:
Array.prototype.forEach().
Array.prototype.join().
String.prototype.split().
Try
var filtered = {};
var url = "http://mywebsite.com/products/filter?style=7-1-2&price=4-5-7&brand=48-12-5&color=8-4";
var filters = url.split("?")[1].split("&");
filters.map(function(val) {
filtered[val.split("=")[0]] = val.split("=")[1].split("-").join(",")
});
console.log(filtered);
var filtered = {};
var url = "http://mywebsite.com/products/filter?style=7-1-2&price=4-5-7&brand=48-12-5&color=8-4";
var filters = url.split("?")[1].split("&");
filters.map(function(val, i) {
filtered[val.split("=")[0]] = val.split("=")[1].split("-").join(",");
document.body.innerText += (Object.keys(filtered)[i].toString() +": "+ filtered[val.split("=")[0]]) + "\n"
});
I want to count number of occurence of BB code like word (example: [b] [/b]).
I tried
(str.match(/\[b\]/g) str.match(/\[\/b\]/g))
None of this worked, please help !!!
Edit
document.getElementById('textarea').value = 'HIiiiiiiiiiii [b]BOld[/b]';
var str = document.getElementById('textarea').value;
Answer:
if (str.match(/\[b\]/g).length == str.match(/\[\/b\]/g)).length) {alert("Fine");}
This regex will match a BB code opening tag:
str.match(/\[[a-z]*\]/g)
Edit: Here's some code that will do exactly what you want including creating an array of errors listing all missing closing tags. This code uses the underscore library for the groupBy() call.
jsFiddle
var bbcode = 'HI[i]iii[i]iii[/i]iii [b]BOld[/b] yahhh [img]url[/img]';
var matches = bbcode.match(/\[[a-z]*\]/g); //get the matches
var tags = _.groupBy(matches, function(val) {
val = val.substring(1, val.length-1);
return val;
});
var errors = [];
for (var tag in tags) {
var regex = '\\\[/' + tag + '\\\]';
if (bbcode.match(regex).length != tags[tag].length) {
errors.push('Missing a closing [/' + tag + '] tag');
}
}
console.log(errors);
Replace occurences until there aren't any; keep track of the amount on the way:
var regexp = /\[[a-z]\](.*?)\[\/[a-z]\]/i;
var str = "test [b]a[/b] test [i]b[/i] [b]d[/b] c";
var newstr = str;
var i = 0;
while(regexp.test(newstr)) {
newstr = newstr.replace(regexp, "");
i++;
}
alert(i); // alerts 3