How to know the iteration in v-for - vue.js

i'm in Vue.js
I made a radio input component, I use a v-for to display all the input and label, I would like to know if I can tell it to pass the checked attribute to the element from the first iteration of the v-for loop
<div v-for="(option) in options" :key="option.name">
<label class="form-check-label mr-2" :for="option.for">
{{ option.name }}
</label>
<input
v-model="selectedChoice"
class="mr-4"
type="radio"
name="radio"
:id="option.for"
/>
</div>
Thanks for your help

if I understand you correct you want to check your first radio button from your v-for.
You have two options to achieve that:
First option
You can set selectedChoice to your first choice like this:
data() {
return {
options: ['yourChoice1', 'yourChoice2'] //you have to set your array in here
selectedChoice: 'yourChoice1',
}
}
Second option
You set your data prop to the first item in your array - this is able because you're using v-model - you do it like this:
this.selectedChoice = this.yourChoice[0]
Hopefully this helps you out - please let me know!

Related

Use unknown key in the v-model in vue js for loop

I have a dynamically made object of facets.
An example of the data could be:
facets: {
type: ['type1', 'type2', 'type3'],
color: ['color1', 'color2']
}
I also have an empty object for filters.
I then loop over the facets object and make checkbox groups for each facet. I want the v-model to be filters."name of the facet", so: filters.type and filters.color. I do not know the names forehand. I tried using the key in a loop but that does not work.
My loop looks like this:
<li v-for="(facet, facetKey, facetIndex) in facets" class="filter-item">
<strong>{{ facetKey }}</strong>
<div v-for="(value, valueIndex) in facet" class="form__fieldset" :key="valueIndex">
<div class="form__field-wrap">
<input type="checkbox" v-model="filters[facetKey]" :id="value.toLowerCase().trim()" :value="value">
<label :for="value.toLowerCase().trim()">{{ value }}</label>
</div>
</div>
</li>
If I hardcode v-model to filters.type, It works as intended. Has anyone achieved this type of dynamic v-models?
Populate filters with your facets properties
filters = ref({
...facets.value
})
Here is the playground link to a working example

Input with datalist calling twice

I'm new to Vue and am trying to build a form with a datalists. The code I've written seems to work fine but I'm not sure why the dropdown list will appear twice. Once when nothing is typed into the input where it will show all the options available, and the second time when an option is chosen and the dropdown will show only the options that match the one typed. Is there a way to get rid of the second dropdown, where it will only show the dropdown once?
Template
<input list=list1 v-model="test">
<datalist id=list1>
<option v-for "item in items" :value="item" :key="item"></option>
</datalist>
Script
export defaults{
data(){
items: [1,2,3,4,5],
test: ''
}
}
Try using {{ item }} instead of binding :value to show and populate the value.
<div>
<input type="text" list="list1" v-model="test" #change="onChange()" />
<datalist id="list1">
<!-- use normal {{ item }} here without binding value-->
<option v-for="item in items" :key="item">{{ item }}</option>
</datalist>
</div>

Validate vue-select with vee-validate

I'm new to VueJS.
I'm trying to validate vue-select using vee-validate.
I've tried to validate it manually but of course its not a good approach.
So, I tried to use vuelidate but couldn't get the desired result.
Now i'm trying to use vee-validate. Validation works fine as desired
but the issue is v-model.
I created a global variable product, to calculate the length of array, and passed it in v-model. So that when Its empty product's value will be zero and i can return desired result from vee-validation.
Here's the .vue html part.
<ValidationObserver>
<form #submit.prevent="add">
<div class="row row-xs mx-0">
<label class="col-sm-4 form-control-label">
<span class="tx-danger">*</span> Add product(s):
</label>
<div class="col-sm-8 mg-t-10 mg-sm-t-0">
<ValidationProvider rules="required" v-slot="{ errors }">
<v-select
name="product"
placeholder="Add product(s)"
:options="availableProducts" <-- here is the options array
:reduce="name => name"
label="name"
#input="setSelected"
v-model="product" <-- this calculates length and pass it to vee **extends**
>
</v-select>
<div v-for="error in errors" :key="error"> {{ error }} </div>
</ValidationProvider>
</div>
<!-- col-8 -->
</div>
</form>
</ValidationObserver>
Here's validation.js file
import { extend } from 'vee-validate';
extend('required', value => {
console.log(value);
return value > 0;
});
I don't want this product value there. I know its not a good approach as well. I can't pass whole array to v-model because then I can't push options in it. I can't pass a single option to v-model as well then I won't get desired result.
All I want to validate v-select when options array is empty. Any suggestions?
Veevalidate doesn't validate directly on select elements. This is my workaround.
You should create a v-field "hidden" input and a visible select v-model element. The veevalidate will take place on the v-field.
Here is an example.
<v-field type="text" class="form-control disabled" name="expirationMonth" v-model="expirationMonth" :rules="isRequired" style="display:none;"></v-field>
<select v-model="expirationMonthUI" class="form-control" #click="synchExpirationMonthUI">
<option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
<option value="April">April</option>
<option value="May">May</option>
<option value="June">June</option>
<option value="July">July</option>
<option value="August">August</option>
<option value="September">September</option>
<option value="October">October</option>
<option value="November">November</option>
<option value="December">December</option>
</select>
<error-message name="expirationMonth"></error-message>
Then add this to your methods to synch both together.
synchExpirationMonthUI() {
this.expirationMonth = this.expirationMonthUI;
}
I have found a way of doing this, with the Rendering Complex Fields with Scoped Slots from the Vee-Validate documentation. And using the bindings from Vue Select, it looks something like this:
<Field name="supportType" v-slot="{ field }" v-model="supportType">
<v-select :options="mediaTypes" label="name" :reduce="mediaType => mediaType.id" v-bind="field">
</v-select>
</Field>
As you can see, I am using here the name, v-slot and v-model for the Field from Vee-Validate, as normal. But the v-slot is very important as it carries the information from Vue Select to Vee-Validate, or at least I think so.
On the other hand I use the options, label, reduce and v-bind from Vue Select, these I use to handle the information. So with the :options I select my dataset, with label I tell Vue Select which label to select and show from the dataset, with :reduce I tell Vue Select what will be the value of the select tag and finally use v-bind to bind the value of the select to the Vee-Validate field. So the information used on the :reduce property will be displayed on the v-model="supportType".
I tested it with a button and it worked. And I liked this way so it is not that messy and I can use the validation and other things as usual.
Hope this helps anyone.
PD: I am using Vue 3, and the latest package of both Vee-Validate and Vue Select, as of today.

v-bind object's properties in radio buttons can't render correctly

The radio buttons' behavior is not as I expected when I am being lazy to use v-bind to dynamically bind the properties of the options to the template.
I am trying to dynamically render the options by an javascript object. However, it behaves differently when I am binding the properties differently. Even after checking the output HTML, I am not sure why the problem exists.
This is the Vue instance for backend data.
const app = new Vue({
el: '#app',
data: {
inputs: {
radioDynamic: '',
radioDynamicOptions: [
{
id: 'Light',
label: 'Blue',
value: 'Light',
},
{
id: 'Dark',
label: 'Red',
value: 'Dark',
},
],
},
},
template: `
<div>
<h4>Radios Dynamic Options</h4>
<!-- case 1: It works fine when I bind properties individually>
<template v-for="(option, index) in inputs.radioDynamicOptions">
<input v-model="inputs.radioDynamic" type="radio" :value="option.value" :id="option.value">
<label :for="option.value">{{ option.label }}</label>
<br v-if="index < inputs.radioDynamicOptions.length">
</template>
-->
<!-- case 2: the options are rendered as a single radio button which is not able to function correctly when I bind the object directly with v-bind="object".
<template v-for="(option, index) in inputs.radioDynamicOptions">
<input v-model="inputs.radioDynamic" type="radio" v-bind="option">
<label :for="option.value">{{ option.label }}</label>
<br v-if="index < inputs.radioDynamicOptions.length">
</template>
-->
<p><strong>Radios:</strong>{{ inputs.radioDynamic }}</p>
</div>
`,
})
<case 1 HTML output>
<h4>Radios Dynamic Options</h4>
<input type="radio" id="Light" value="Light">
<label for="Light">Blue</label>
<br>
<input type="radio" id="Dark" value="Dark">
<label for="Dark">Red</label>
<br>
<p><strong>Radios:</strong>Dark</p>
<case 2 HTML output>
<h4>Radios Dynamic Options</h4>
<input type="radio" id="Light" label="Blue" value="Light">
<label for="Light">Blue</label>
<br>
<input type="radio" id="Dark" label="Red" value="Dark">
<label for="Dark">Red</label>
<br>
<p><strong>Radios:</strong></p>
I expect the case 2 method, which is using v-bind="object", should generate the same result like v-bind:id="object.id" v-bind:value="object.value"
But it turns out that I can't select the radio button individually and the selected value isn't pushed into the array.
This is my very first question here. Please forgive if my expression or format isn't good or qualified enough. Thanks and have a great day~
not sure what you're trying to achieve here, but i would recommend going over the functionality of v-bind and v-model. v-bind enables passing dynamic data to html attributes. v-on allows listening to DOM events, and v-model results in whats called - two way data binding, which is basically a combination of both v-bind and v-on. with that said, using both v-model and v-bind on the same element feel's a bit odd.
you might achieve what you desire in the 2nd case following way:
<template v-for="(option, index) in inputs.radioDynamicOptions">
<input v-model="inputs.radioDynamic" type="radio" v-bind:value="option.id">
<label :for="option.value">{{ option.label }}</label>
<br v-if="index < inputs.radioDynamicOptions.length">
</template>
UPDATE:
i believe that the issue your'e experiencing is a result of one main difference between object (which you can learn more about here) and primitive types.
long story short, in JavaScript primitive types like the strings you pass in case 1 are being passed by value and so behave as expected. while passing object's to v-bind you actually pass a pointer to that object and so when you click a radio button, you manipulate the same place in memory in charge of both radio buttons, which results with the unexpected behavior you experience.
Why do you expect that v-bind="options" will work on <input/>? This form is used for custom components only.
From documentation:
Components In-Depth → Props → Passing the Properties of an Object
If you want to pass all the properties of an object as props, you can use v-bind without an argument (v-bind instead of v-bind:prop-name). For example, given a post object:
post: {
id: 1,
title: 'My Journey with Vue'
}
The following template:
<blog-post v-bind="post"></blog-post>
Will be equivalent to:
<blog-post
v-bind:id="post.id"
v-bind:title="post.title">
</blog-post>
If you want to bind dynamic/javascript values to an usual element, you should use :value="option.value" :id="option.id" as shown in your first example.

Vue v-model not reactive with BS4 radio button group

I'm hoping I'm just missing something simple because I've been looking at this for too long, but I'm stumped.
I have a form with inputs bound to vuejs. I have a group of 2 radio buttons for selecting the "gender", and the binding is working perfectly. If I click on either of the radio buttons, I can see the data change in the vue component inspector.
But I'm trying to change the radio buttons to a Bootstrap 4 button group, and can't seem to get the v-model binding to work. No matter what I try, the gender_id in my vue data is not getting updated when I click either of the buttons in the button group.
The form input values are being fed in through vue component properties, but for simplicity, my data for the radio buttons/button group would look like this:
export default {
data() {
return {
genders: {
1: "Men's",
2: "Women's"
},
gender_id: {
type: Number,
default: null
}
}
}
}
Here is the code I have for the radio button version (which is working properly):
<div class="form-group">
<label>Gender:</label>
<div>
<div class="form-check form-check-inline" v-for="(gender, key) in genders" :key="key">
<input type="radio"
class="form-check-input"
name="gender_id"
:id="'gender_' + key"
:value="key"
v-model.number="gender_id">
<label class="form-check-label" :for="'gender_' + key">
{{ gender }}
</label>
</div>
</div>
</div>
Here is the button group version that is not properly binding to the gender_id data in vue.
<div class="form-group">
<label>Gender:</label>
<div>
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-outline-secondary" v-for="(gender, key) in genders" :key="key">
<input type="radio"
class="btn-group-toggle"
name="gender_id"
:id="'gender_' + key"
:value="key"
autocomplete="off"
v-model.number="gender_id">
{{ gender }}
</label>
</div>
</div>
</div>
I've been using the following Boostrap 4 documentation to try to get this working.
https://getbootstrap.com/docs/4.0/components/buttons/#checkbox-and-radio-buttons
In the documentation for button groups they don't even include the value property of the radio inputs, whereas they do include it in the documentation for form radio buttons.
https://getbootstrap.com/docs/4.0/components/forms/#checkboxes-and-radios
Is this for simplicity or do button groups of radio buttons not even return the value of the checked button?
I see other threads stating that buttons groups are not meant to function as radio buttons, but if that's true for BS4, then why would Bootstrap have button groups with radio buttons as they do in their documentation referenced above? If you can't retrieve the checked state, then why not just use a <button> instead of <label><input type=radio></label>?
Any ideas as to what I'm doing wrong and/or not understanding correctly?
Thanks so much!
Thanks so much to #ebbishop for his helpful insights.
The issue was related to vue and bootstrap both trying to apply javascript to the buttons in the button group.
To get around this issue, it was as simple as removing data-toggle="buttons" from the button group. By removing the data-toggle attribute, the bootstrap js is not applied and vue can manage the button group.
Nothing is actually wrong your use of v-model here.
However: you must add the class "active" to the <label> that wraps each radio-button <input>.
See this fiddle for a working example.
Is that what you're after?