build a v-checkbox list in Vue - vue.js

I need to build a to-do list with check boxes but instead of using an array that pulls each items as if it was a separate row these are all separate columns. So the object looks like
[{"InterProgramatic":false,"IntraProgramatic":false,"MultiInstitution":false,"Accepted":true,"Rejected":false,"Cancer_Related":true}]
How can I build the Checkboxes using a v-for loop?
my array is simply
statusItems: []
If each item was in a separate row then I can assign a separate id, but is there an easier way to do this in Vue? To save the data I planned on just sending back to the Web API the statusItems object and parsing it there so I was hoping to bind it if possible.
I can use
v-for="(item, index) in statusItems" :key="index"
<v-checkbox
:key="index"
:label="item"
color="success"
v-bind:id="status"
v-model="statusItems[key].checked"
#change="statusChange(statusItems[key])"
>></v-checkbox>
to build the checkboxes but not sure how to bind it. Thanks for the help

Is that what your trying to do ?
https://codesandbox.io/s/vue-template-tkx60?fontsize=14
To bind the v-model, you need to use the array index or the object key.

Related

How to use `v-if` and `v-for` on the same element?

Hi I'm trying to figure out how to use v-if on a iterated element which also uses v-for. I need to check if the current element has any of a series of classes, which are numbers.
so the classes of each article would be:
<article class="post-item post-guide 12 22 19 30 55">...
this is the HTML that renders all:
<article v-if="showIfHasClass" :class="'post-item post-guide ' + guide.categories.toString().replace(/,/g, ' ')"
v-for="(guide, index) in guides" :key="index">
<header>
<h1 class="post-title">
{{ guide.title.rendered}}
</h1>
</header>
</article>
I have tried with methods that check the class of all elements, that works, but i'm trying to use a clean Vue built-in solution with v-if without success, i'm not able to retrieve the class of this in a successful way.
Should showIfHasClass be a computed property? I have tried with that too... but it seems, I'm missing something along the way.
my data I have to check against is an array:
data:{
guides: [...]
selectedCategories: [1, 22, 33, 100, 30];
}
or maybe it is better to directly loop over the guides and check if they have the selectedCategory or not, then remove the element from the guides data array?
What is more effective?
Besides the option to create an additional filtered computed (effectively eliminating the need to use v-for and v-if on the same element), you also have a template level way of dealing with such edge-cases: the <template> tag.
The <template> tag allows you to use arbitrary template logic without actually rendering an extra element. Just remember that, because it doesn't render any element, you have to place the keys from the v-for on the actual elements, like this:
<template v-for="(guide, index) in guides">
<article v-if="isGuideVisible(guide)"
:key="index"
class="post-item post-guide"
:class="[guide.categories.toString().replace(/,/g, ' ')]">
<header>
<h1 v-text="guide.title.rendered" />
</header>
</article>
</template>
isGuideVisible should be a method returning whether the item is rendered, so you don't have to write that logic inside your markup. One advantage of this method is that you can follow your v-if element with a fallback v-else element, should you want to replace the missing items with fallback content. Just remember to also :key="index" the fallback element as well.
Apart from the above use-case, <template> tags come in handy when rendering additional wrapper elements is not an option (would result in invalid HTML markup) (i.e: table > tr > td relations or ol/ul > li relations).
It's mentioned here as "invisible wrapper", but it doesn't have a dedicated section in the docs.
Side note: since you haven't actually shown what's inside guide.categories, I can't advise on it, but there's probably a cleaner way to deal with it than .toString().replace(). If guide.categories is an array of strings, you could simply go: :class="guide.categories".
I think the most Vue way is to create a computed property with filtered items from selected categories, then use that in v-for loop (the idea is to move the business logic away from template).
computed: {
filteredItems(){
return this.guides.filter(e => this.selectedCategories.includes(e.category))
}
}
Also, as a note, it is not recommended to use v-if and v-for on the same element, as it may interfere with the rendering and ordering of loop elements. If you don't want to add another level of nesting, you can loop on a 'template' element.
<template v-for="item in items">
// Note the key is defined on real element, and not on template
<item-element v-if='condition' :key="item.key"></item-element>
</template>

Display one object property value, and show another one on hover

the question I have might be hard to understand, so please help me re-organize the question if you can see the better way to put it in.
So, I am building a registration platform.
(1) First, I receive an array of objects of cases the user can sign time to.
(2) Each object consists of 2 properties, "name", "description".
(3) I store the array in the data, end use it in the element provided by a picker called "vue-multiselect", which basically accepts the array and loops over the objects and displays them.
(4) As you can see, it displays both properties and values, which I am trying to avoid. My question is, is it possible to pass only the "name" value into the picker, and display the description value when hovering the first value?
You can find this use case documentation here: https://vue-multiselect.js.org/#sub-custom-option-template
<multiselect v-model="value"
deselect-label=""
select-label=""
placeholder=""
selected-label=""
:show-pointer="true"
:options="projectCases">
<template slot="option" slot-scope="{ option }">
<strong :title="option.description">{{ option.name }}</strong>
</template>
</multiselect>
ps: I use title attribute to implement display-on-hover functionality. you can use any other tooltip library as well.

Vue.js v-for loop binding items objects in array and update on change

I have a component and am using a v-for loop to loop through and object array at the $root level of my app to populate a list.
In other components in my app I'll EventBus.$emit data to update tables in my database. That means the $root array data updates.
Is there a way to bind or map the v-for list I created to detect and update using the index or another method?
Here is the example loop and example $root data.
I guess I'm hoping there's a way to connect an object in an array by using [index]
<v-list-item-content v-if="this.$root.people">
<div v-for="(item, index) in this.$root.people" :key="item.id">
<div>
<span v-html="this.$root.people[index].value"></span>
</div>
</div>
</v-list-item-content>
My array looks like this.
people:Array[2]
0:Object
event_id:6
submission_values:Array[4]
0:Object
value:"Danny"
1:Object
2:Object
3:Object
I suppose if people is already reactive then you should look at how you update this array. There are some caveats about updating a reactive array in VueJS, please take a look at the official documentation

vuejs expression is not working correctly

what is wrong with my expressions? I am making a rest api call, which works fine. Data loads and gets written to console. I am simply trying to get that data on screen. I can but its not correct. It either shows all of the data. I am only trying to get the first item in the array. items.Name does not work, but it does if I do a v-for="item in items". Regardless it loads everything. When I add a [0] to get the first element, it simply removes all the text except the first letter of the object in the array.What do I need to do?
<p>{{items.Name}}</p>
Please, read the docs about list rendering
https://v2.vuejs.org/v2/guide/list.html
If you have an items array of objects, then you can loop over it in your HTML by using v-for, or directly access each entry by specifying the index in the expression: {{ items[0].Name }}
<ul>
<li v-for="item in items" :key="item.ID">{{ item.name }}</li>
</ul>
Notice you're using item, not items, inside the <li> tag, because you instructed v-for to assign the cursor to that variable.

In VueJS, v-for doesn't create discrete items when new data is assigned

Currently, when I have a v-for loop like this:
<li v-for="record in records">
<my-vue-list-item :vue-title="record.title"></my-vue-list-item>
</li>
and I update the data driving the v-for (i.e. assign a new value to records), it doesn't actually create new list items based on the new data. It just updates some of the properties on the list item components components.
Here is a JSFiddle illustrating what I'm talking about. Try expanding one of the buttons (e.g. click "Expand Apple"), then click on "Set 2" to see that even when the list items switch, the component stays expanded.
What's the recommended way of getting around this behavior? I want each new list item (when the data is swapped out) to appear like new. (In the fiddle example, which I load a new set, it should not be already expanded.)
You need to let the Vue components know that the item is different. As far as they know, they're still rendering the same element index from the same list.
You can do this by specifying the key in your v-for iterator...
<li v-for="item in items" :key="item">
https://jsfiddle.net/ahxf44jk/21/