I tried to play your code in the snippet below. From what I could notice there are two more serious errors that prevent the operation.
On the 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 not saving the result in a variable.
On the line:
item.nome.toLowerCase().indexOf(searchString)
The method String.indexOf()
looks 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 the Array.indexOf()
which has a similar function, but looks for the occurrence within an array. So I think what you want to use on that line is:
searchString.indexOf(item.nome.toLowerCase())
EDIT
I modified the code to behave like a LIKE
and as a OR
. The function was thus:
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 strings, as it is used more than once in the code. This function could be elsewhere, outside the computedProperty
(maybe I should even).
let strings = this.myGlobalStuff.searchArray.map(sanitize);
Sanitizes 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 the elements whose function returns a value Truthy (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 to function
in the elements of Array
and returns true
if any of the function returns are Truthy. I mean, it works like a OR
(and the Array.every(function)
functions as a 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 has been found 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 a binary exactly opposite of 0 (See about complement of 2).
(-1 >>> 0).toString(2) // "11111111111111111111111111111111"
(0).toString(2) // "00000000000000000000000000000000"
To understand the >>> 0
see this reply from Soen
So if you apply one NOT
torque (with the operator ~
), any number other than -1 shall be !== 0
that is a value Truthy and -1 will be false. Then, in the conversion to boolean
:
x.indexOf(y) !== -1
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>
<div id="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>
Create a snippet with functional code to make it easier. Is this code you posted a computedProperty? A method?
– fernandosavio
I’ll try to improve, it’s a computed
– haykou