I tried to reproduce your code in the snippet below. As far as I can tell you have two more serious errors that prevent it from working.
On line:
searchString.map(searchString => searchString.trim().toLowerCase());
The method Array.map()
returns a new array with the callback result applied to all array elements. In your case, you are doing the calculation and you are not saving the result to a variable.
On line:
item.nome.toLowerCase().indexOf(searchString)
The method String.indexOf()
searches for an occurrence of a substring in another string, but by the logic of your code it seems to me that you want to use Array.indexOf()
" that has similar function, but looks for the occurrence inside an array. So I believe that what you want to use in this line is:
searchString.indexOf(item.nome.toLowerCase())
EDIT
I have modified the code to behave as a LIKE
and as a OR
. The function looks like this:
function produtosFiltrados() {
let sanitize = str => str.trim().toLowerCase();
let strings = this.myGlobalStuff.searchArray.map(sanitize);
return this.produtos.filter(function(item) {
let nome = sanitize(item.nome);
return strings.some(str => ~nome.indexOf(str));
});
}
Explanation of the code:
let sanitize = str => str.trim().toLowerCase();
It only saves the function that sanitizes the string, since it is used more than once in the code. This function could be somewhere else, out of computedProperty
(maybe it should be).
let strings = this.myGlobalStuff.searchArray.map(sanitize);
Sanitize all search terms before using them.
return this.produtos.filter(function(item) {
let nome = sanitize(item.nome);
return strings.some(str => ~nome.indexOf(str));
});
This is where it all happens:
-
this.produtos.filter(...)
will return an array only with elements whose function returns a truthy value. (which when converted to boolean is true). Ex .:
// Filtra apenas os números ímpares
[0, 1, 2, 3].filter(x => x % 2) // [1, 3]
-
strings.some(...)
, the method Array.some(function)
applies function
to elements of Array
and returns true
if any of the function returns is truthy . That is, it works as a OR
(and Array.every(function)
/ a> works like AND
, just for curiosity). Ex.:
// Testa se tem algum número ímpar no array
[0, 1, 2, 3].some(x => x % 2) // true
[0, 2, 4, 6].some(x => x % 2) // false
-
~nome.indexOf(str)
, the method String.indexOf(substring)
returns the position of the substring inside the string or -1 if the substring does not exist inside the string. That said, to know if the substring was found, we just test if x.indexOf(y) !== -1
, however, as a curiosity, if you convert -1 to a binary representation you will realize that it is an exactly opposite binary of 0 (See about 2's complement ).
(-1 >>> 0).toString(2) // "11111111111111111111111111111111"
(0).toString(2) // "00000000000000000000000000000000"
To understand >>> 0
see this SOEn response
So if you apply a NOT
binary (with the ~
operator), any number other than -1 will !== 0
which is a value truthy and -1 will be fake. Then, in the conversion to boolean
:
x.indexOf(y) !== -1
It is equivalent to:
~x.indexOf(y)
Then the function:
return this.produtos.filter(function(item) {
let nome = sanitize(item.nome);
return strings.some(str => ~nome.indexOf(str));
});
Means:
Filter all products whose name contains any of the search terms.
Code working:
new Vue({
el: '#app',
data: {
myGlobalStuff: { // fake da Global
searchArray: ["1", "5"]
},
produtos: [
{id: 1, nome: "Produto 1"},
{id: 2, nome: "Produto 2"},
{id: 3, nome: "Produto 3"},
{id: 4, nome: "Produto 4"},
{id: 5, nome: "Produto 5"},
{id: 6, nome: "Produto 6"},
]
},
computed: {
produtosFiltrados: function() {
// Salva a função apenas por praticidade
let sanitize = str => str.trim().toLowerCase();
let strings = this.myGlobalStuff.searchArray.map(sanitize);
return this.produtos.filter(function(item) {
let nome = sanitize(item.nome);
return strings.some(str => ~nome.indexOf(str));
});
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script><divid="app">
<strong>Produtos</strong>
<ul>
<li v-for="p in produtos" :key="p.id">
[{{ p.id }}] {{ p.nome }}
</li>
</ul>
<strong>Produtos Filtrados</strong>
<ul>
<li v-for="p in produtosFiltrados" :key="p.id">
[{{ p.id }}] {{ p.nome }}
</li>
</ul>
</div>