Reputation: 782
I'm trying to filter data by name using both an input field and an alphabetical list. The text input field filtration is working fine, however, filtering by the first letter of the string using .startsWith()
is refusing to work. I'm still new to this and can't figure it out.
What am I doing wrong? Here's the fiddle.
<div id="app">
<h1>Authors</h1>
<div class="letters-list">
<div class="letters-wrap" v-for="letter in letters" :key="letter">
<div v-if="isAuthorLink(letter)" class="has-data">
<input type="radio" :value="letter" v-model="lettersFilter">
<label :for="letter">{{ letter }}</label>
</div>
<div v-else>{{ letter }}</div>
</div>
</div>
<div class="search-wrapper">
<input type="text" v-model="searchByName" placeholder="Search.." />
</div>
<div class="list-inner">
<div v-for="author in authorsFilter" :key="author.id">
<h5><a :href="author.link" v-html="author.name"></a></h5>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: function () {
return {
authors: [
{
"id": 77,
"link": "http://my-site/authors/anonymous/",
"name": "Anonymous",
"slug": "anonymous"
},
{
"id": 72,
"link": "http://my-site/authors/ferdinand-marcos/",
"name": "Ferdinand Marcos",
"slug": "ferdinand-marcos"
},
{
"id": 75,
"link": "http://my-site/authors/john-f-kennedy/",
"name": "John F. Kennedy",
"slug": "john-f-kennedy"
},
{
"id": 67,
"link": "http://my-site/authors/john-maxwell/",
"name": "John Maxwell",
"slug": "john-maxwell"
}
],
searchByName: '',
lettersFilter: ''
}
},
computed: {
letters() {
let letters = []
for(let i = "A".charCodeAt(0); i <= "Z".charCodeAt(0); i++) {letters.push(String.fromCharCode([i]))}
return letters
},
authorsFilter() {
if(this.searchByName){
return this.authors.filter((item)=>{
return item.name.toLowerCase().includes(this.searchByName.toLowerCase())
})
} if(this.lettersFilter){
return this.authors.filter((item)=>{
return item.name.toLowerCase().startsWith(this.lettersFilter.toLowerCase());
})
} else {
return this.authors;
}
},
},
methods: {
isAuthorLink(letter) {
return this.authors.some(aut => aut.name.startsWith(letter))
},
}
})
</script>
Upvotes: 0
Views: 1657
Reputation: 29132
Yom S. is correct, the main problem is that your <label>
is not associated with your <input>
. The <input>
itself is hidden by your CSS so only the <label>
is clickable. The filtering is never triggered.
An alternative to using a for
/id
is to put the <input>
inside the <label>
.
<label>{{ letter }}<input type="radio" :value="letter" v-model="lettersFilter"></label>
This creates an implicit link between the <input>
and <label>
such that clicking on the <label>
counts as a click on the <input>
.
On an unrelated note, I would advise not using v-html
if you can help it.
Upvotes: 1
Reputation: 9200
You need the id
attribute on the input elements for the label
s to associate with; without one, the @input
event won't get emitted, and the value
not updated.
<div v-if="isAuthorLink(letter)" class="has-data">
<input :id="letter" type="radio" :value="letter" v-model="lettersFilter">
<label :for="letter">{{ letter }}</label>
</div>
Quoting the docs on <label>
's for
attribute:
The
id
of a labelable form-related element in the same document as the<label>
element. The first element in the document with anid
matching the value of the for attribute is the labeled control for this label element, if it is a labelable element. If it is not labelable then thefor
attribute has no effect. If there are other elements which also match theid
value, later in the document, they are not considered.
Upvotes: 1