https://jsfiddle.net/72tnpa0o/
<div id="filter-by-example">
<label>Cool</label><input type="checkbox" v-model="cool">
<label>notCool</label><input type="checkbox" v-model="notCool">
<ul>
<li v-for="user in users | filterBy cool in 'cool' | filterBy notCool in 'notCool'">
{{ user.name }}
</li>
</ul>
</div>`
new Vue({
el: '#filter-by-example',
data: {
name: '',
users: [
{
name: 'Bruce',
cool: true,
notCool: false
},
{
name: 'Chuck',
cool: false,
notCool: true
},
{
name: 'Jackie',
cool: true,
notCool: false
}
]
}
})
I have an example up at the fiddle link above. I'm able to sort via the input checkboxes, but unchecking the filters doesn't reset to the original results.
Does anyone know how after unchecking a filter button to get the full array to render?
The main issue here is that the logic of the selector is wrong: as it stands now, if you deselect both checkboxes, you will get the items that are both cool and notCool. The reason it's working in the beginning is because there's an error in your code (open the console, you will see errors there): both cool and notCool are undefined at the beginning.
So first you need to outline what do you want. Once you've done this, you can use a function to filter instead of using the out-of-the-box one, something like this:
<li v-for="user in users | filterBy filterCool">
{{ user.name }}
</li>
And filterCool should be like:
filterCool: function (element, i, list) {
if (this.showCool && element.cool) return true;
if (this.showNotCool && element.notCool) return true;
if (!this.showNotCool && !this.showCool) return true;
return false;
}
Not a perfect solution right now, but a good way to start. Check this: https://jsfiddle.net/72tnpa0o/5/
The filter does not apply if the :false-value checkbox is empty
Try change this:
<input type="checkbox" v-model="cool">
<input type="checkbox" v-model="notCool">
by
<input type="checkbox" :false-value="" v-model="cool">
<input type="checkbox" :false-value="" v-model="notCool">
Also make sure to add an key for your list items so that vue can track each item and show relevant data (https://v2.vuejs.org/v2/guide/list.html#key).
Vue 2:
<li
v-for="(user, key) in users | filterBy filterCool"
:key="key"
>
{{ user.name }}
</li>
Vue 1:
<li
v-for="user in users | filterBy filterCool"
track-by="$index"
>
{{ user.name }}
</li>
Related
I have a fix number of checkbox which I am binding using for loop.
<ul>
<li *ngFor="let chk of checkboxes">
<input type="checkbox" [id]="chk.id" [value]="chk.value"/>
<label [for]="chk.id">{{chk.name}}</label>
</li>
</ul>
what I am looking for is using template driven form to get a value all of selected checkboxes, something like following
{
selected:[
checkboxValue1,
checkboxValue2,
checkboxValue3,
]
}
NOTE:
I am able to use Reactive form to generate a FormGroup->FormArray which generates the following form value
{
checkboxes:[
{
id: checkboxId1,
value: checkboxValue1,
selected: true,
},
{
id: checkboxId2,
value: checkboxValue2,
selected: false,
},
{
id: checkboxId3,
value: checkboxValue3,
selected: true,
}
]
}
Which I am then filtering out with selected==true.
I was wondering how to do something similar with template driven form.
You can attach a template variable to the checkbox and then query it using #ViewChildren
<ul>
<li *ngFor="let chk of checkboxes">
<input #checkbox type="checkbox" [id]="chk.id" [value]="chk.value"/>
<label [for]="chk.id">{{chk.name}}</label>
</li>
</ul>
Then in your component class:
export class MyComponent {
#ViewChildren('checkbox')
checkboxes!: QueryList<ElementRef>
}
And to access your array:
const selected = this.checkboxes
.map(t => t.nativeElement)
.map(checkbox => checkbox.checked
I know that "v-if" must avoid with "v-for" but not sure about "v-show" because it is just to toggle the display attribute.
This is the code in case anyone wants to know. Basically, I try to switch 3 different types of filter list. The code runs fine but I just wanna know if it should be avoid like "v-if".
<template>
<button
v-for="(filter, index) in filterList" :key="index"
#click="chosenFilter = filter.name"
>
{{ filter.name }}
</button>
<div
v-for="(filter, index) in filterList" :key="index"
v-show="chosenFilter === filter.name"
>
<div v-for="(listItem, index) in filter.list" :key="index">
{{ listItem }}
</div>
</div>
</template>
<script>
data () {
return {
filterList: [
{ name: 'Type 1', list: [] },
{ name: 'Type 2', list: [] },
{ name: 'Type 3', list: [] }
],
chosenFilter: 'Type 1'
}
}
</script>
From the official style guide: https://v2.vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential
There are 2 points in which it's not a good practice to use that, the 2nd one is interesting: To avoid rendering a list if it should be hidden. This one is basically fine since you're not doing heavy JS rendering, just basic CSS toggling.
So yeah, I'd say it's correct to have a v-show (and ESlint is not complaining btw).
But IMO, you can solve this kind of behavior in pretty much all cases with a computed: your filter button could be selected with an ID and your list rendering could be filtered with a filter here.
Replace #click="chosenFilter = filter.name" with #click="chooseFilter and get the ID (thanks to $event) of the item you've clicked on, then filter your list with the selected filter.
I'd like to disable specific link in automatically rendered list in Vue.js conditionally, here is what I have at the moment:
<ul>
<li class="nav-item" :key="id" v-for="(item, id) in listOfItems">
<a class="nav-link" :id="item.id">{{ item.name }}</a>
</li>
</ul>
Basically in some conditions I'd like to disable one of the links from the listOfItems and get it back active if this condition is not applicable anymore. If I bind conditional class it applies to each item in the list:
:class="[someCondition = 'something' ? 'disabled' : '']"
How to specify in this condition which item exactly should be disabled if the condition is true?
You could put an additional property on any items you want checked that way:
listOfItems: [
{ id: 1, name: 'name1', checkme: true },
{ id: 2, name: 'name2', checkme: false },
]
Then, using object binding syntax and === since you're doing a comparison:
:class="{ disabled: item.checkme && someCondition === 'something' }"
This a simple to-do list and I am trying to add an id in each <li> that is rendered. Each id should be named different (obviously) but similar name: "id0","id1","id2"...etc
The number comes from the directive v-for="i in items"
I do it like this:
<li :id="`id${i.id}`" v-for="i in items" :key="`id${i.id}`">
Complete code:
<ul class="item-list-ul">
<li :id="`id${i.id}`" v-for="i in items" :key="`id${i.id}`">{{ i }}
<div class="item-butons">
<b-button class="done-btn" #click="strikeItem(i)" size="sm" variant="outline-dark">DONE!</b-button>
<b-button class="delete-btn" #click="deleteItem(i)" size="sm" variant="warning">Delete</b-button>
</div>
</li>
</ul>
My items array:
data () {
return {
items: ["five", "<li>", "should","be","rendered"]
}
}
But when I check in the console the names of the new dynamically created id´s of the <li> they just appear idundefined when in the case of having for example 3 <li> they should appear like this:
id0
id1
id2
However in the console there aren't any errors. It seems that the vue-html simply does not read a number in ${i.id} but just undefined. Why?
If items is just an array of strings, then there is no id property available. The standard idiom in this case is to use the index like so:
<li v-for="(i, index) in items" :id="`id${index}`" :key="index">
Alternatively, you could reshape your data to have ids like:
[{ id: 0, text: 'foo' }, { id: 1, text: 'bar' }, { id: 2, text: 'baz' }]
That could be done as part of a computed property, for example. Note this would also require a few changes to your template.
I'm trying to figure out how to show job.name if the job.name from jobs is also in anotherArray.
<li v-for='job in jobs'>
<template v-if="job.name in anotherArray"
{{ job.name }}
</template>
</li>
note anotherArray is structured the same way as the jobs array. So I want to be checking element.name in anotherArray
How can I do this?
You can use computed to get list of anotherArrayName, then create a method to check using includes
computed: {
anotherArrayName() {
return this.anotherArray.map(item => item.name)
}
},
methods: {
isInclude(name) {
return this.anotherArrayName.includes(name)
}
}
and in template
<li v-for='job in jobs'>
<template v-if="isInclude(job.name)"
{{ job.name }}
</template>
</li>