multiple select box using v-for - vue.js

I have multiple select boxes which are rendered using a v-for loop, what I am trying to do is to store each option value for each select box in an array but when I select an option it only stores the chosen option, not multiple options
<template v-for="(gettailor) in gettailors" :key="gettailor.id">
<div class="col-sm-6" >
<div class="form-floating" >
<p>{{ gettailor.names }}</p>
</div>
</div>
<div class="col-sm-6">
<div class="form-floating">
<select class="form-select shadow-none" id="tailors" v-model="tailors" required>
<template v-for="(item) in gettailor.tailor" :key="item.id">
<option :value="item.id">{{ item.tailor }}</option>
</template>
</select>
<label for="tailors">Choose {{ gettailor.names }}</label>
</div>
</div>
</template>
<script>
import { ref, watch,onMounted } from 'vue';
const tailors = ref([]);
</script>

I think tailors should be an object, then you bind the select value to a value in the object:
<select
class="form-select shadow-none"
id="tailors[]" <-------- generates several selects with same id
v-model="tailors[gettailor.id]" <--------- bind to object value
required
>
Of course you can also use an array, but it does not work well with reactivity if you use loop index as key (if order changes, you don't know where the values came from), and if you use tailor id, you get a sparse array, which is probably hard to work with.

Related

The Bootstrap-vue3 table does not add buttons to each row of data

I'm trying to add a button to the bootstrap table using Vue3, but I ran into the following problem.
The logic of the button is stored in the parent component, and I plan to $emit on the logic from there. But in order for the button to delete a certain row, for example, I need to pass a special ID, I can't pass it to the ID, because I don't understand how to iterate through the data array in the bootstrap table correctly.
Maybe there is a soft and correct way to solve this problem?
ChildComponent.vue
<template>
<div v-if="data.length !== 0">
<div class="card inline" >
<div>
<b-table striped hover :items="data">
<button #click="$emit('remove', hereIneedTheID)">Remove</button>
</b-table>
</div>
</div>
</div>
<div class="card center" v-else>
<h4>No data available in the list</h4>
<button class="btn" #click="$emit('load')">Load list of data</button>
</div>
</template>
<script>
export default {
name: "AppDataList",
emits: ['load', 'remove'],
props: ['data']
}
</script>

Vue2 generated select triggers event for every other selects

I have a Vue2 project with Buefy extension. Then I have an array of objects which is rendered in the template with one select component for each item. Everything works, but if I trigger #input event on one of the select elements it triggers input event for all selects in the list. I dont understand what is wrong with that.
<div v-for="(inv, index) in pendingInvitations" :key="index" class="columns is-desktop">
<div class="column is-4">{{inv.email}}</div>
<div class="column is-4">
<b-field class="mb-5">
<b-select v-if="invitationRoles"
:input="changeInvitationRole(index)"
v-model="pendingInvitations[index].role"
:placeholder="role">
<option v-for="(value, key) in invitationRoles"
:key="key"
:value="value">
{{ value }}
</option>
</b-select>
</b-field>
</div>
</div>
...
changeInvitationRole(index){
console.log(index);
},
If I change the role and there are three items in the list the console.log() writes 0, 1, 2 as indexes for all items. Why it happens to me? I expect only current itmes index in the log.
Try replacing input with change

How to make iterations using v-for directive on nested array (array in array)

I am new to Vue and I came upon a situation that I would like to have some advice on.
In my js file I have some arrays that contain some data that I would like to insert in a table:
const d1=[{col1:"aaa1",col2:"bbb1",col3:"ccc1",col4:"ddd1",col5:"eee1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"}]
const d2=[{col1:"fff1",col2:"ggg1",col3:"hhh1",col4:"iii1",col5:"jjj1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"}]
then I saved the two arrays in another variable called availableData
const availableData=[d1,d2];
my vue instance as follows:
new Vue({
el: '#c1',
data: {
availableData,
}
});
In my HTML I am trying to add a for loop(v-for) in my row div so the row can display each of data in my availableData variable, but I am having some problems trying to pass d1 to the first row and d2 to the second,
<div id="c1" class="columns">
// ...some code
<div class="row" v-for="data in availableData">
<div class="cell">
{{data.col1}}
</div>
<div class="cell">
{{data.col2}}
</div>
<div class="cell">
{{data.col3}}
</div>
<div class="cell">
{{data.col4}}
</div>
<div class="cell">
{{data.col5}}
</div>
</div>
</div>
Of course, the v-for statement is not correct since I am trying to iterate through the availableData array, if I were to write
v-for="data in availableData[i]"
then is there a way to pass a varaible like i to achieve iteration, or is this method not a plausible way to conduct?
You have several solutions to do what you want.
Solution # 1 :
You can alter the availableData to display all data like you want. You have just to flat you array like this : const availableData=[...d1, ...d2];
With such a code your availableData variable will have :
const availableData = [{col1:"aaa1",col2:"bbb1",col3:"ccc1",col4:"ddd1",col5:"eee1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"},
{col1:"fff1",col2:"ggg1",col3:"hhh1",col4:"iii1",col5:"jjj1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"}]
Solution # 2
You can make a double iteration in your template :
<div class="data" v-for="data in availableData">
<div class="row" v-for="row in data">
<div class="cell">
{{row.col1}}
</div>
<div class="cell">
{{row.col2}}
</div>
<div class="cell">
{{row.col3}}
</div>
<div class="cell">
{{row.col4}}
</div>
<div class="cell">
{{row.col5}}
</div>
</div>
</div>

adding component on add button

i am a absolute beginner in vuejs,i have a feature of adding dynamic input fields on click of a button it will keep on adding rows and keeping in mind the counter should be incrementing also so that i can validate on backend, this is my code so far
<div id="settlement_container" class="container-fluid mt-4">
<div class="card rounded-0 shadow-lg">
<div class="card-body p-0">
<div class="card-header px-2">
<div class="row wow fadeIn">
<div class="col-5">
<h3>Add Store Status</h3>
</div>
</div>
</div>
<form class="custom-form-group" action="{{url('stores/addStoreStatusDB')}}" method="POST">
<div class="form-group col-6">
<label for="exampleInputEmail1">Tax</label>
<input type="text" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="tax" placeholder="Tax" required>
</div>
<div class="display-inline">
<div class="form-group col-md-6">
<button #click="addstatus" class="btn btn-primary">Add Rows</button>
</div>
</div>
<div class="display-inline">
<div class="form-group col-md-6">
<button type="submit" class="btn btn-primary">Update Tax</button>
</div>
</div>
<dynamic-rows/>
</form>
</div>
</div>
</div>
{{-- Main layout --}}
#push('script')
<script src="{{ asset('js/app_vue.js') }}" ></script>
<script>
Vue.component('dynamic-rows',{
//accept data inside template
props:['counter'],
//accept data inside template
template:"<label for='exampleInputEmail1'>counter</label>"
});
const app = new Vue({
el: '#settlement_container',
data: {
counter:0
},
component:['dynamic-rows'],
methods:{
addstatus:function(e){
appendDiv=""
e.preventDefault();
alert("inside");
}
}
});
</script>
now i can do this in jquery in 5 minutes , but as i am beginner in vuejs i cant developer the sense of it of how to do it, i have a component and i want to repeat the component every time the button is clicked,
here is the fiddle! fiddle
OK, so a lot going on here and I think it may be easier to break down some of the points in isolation for you to play with and learn.
To add inputs, I think it makes more sense to have the values being in an array. Using Vue, you can iterate through that array to let each array element have its own <input/> while also simply adding another array element to add a new input:
<template>
<div>
<div v-for="(tax, index) in taxes" :key="index">
<input v-model="taxes[index]" />
</div>
<button type="number" #click="add">Add</button>
<p>Count: {{taxes.length}}</p>
</div>
</template>
<script>
export default {
data(): {
return {
taxes: [0]
}
},
methods: {
add() {
this.taxes.push(0);
}
}
});
</script>
Now with regards to the counter, I don't know what you mean validate on the backend. You could add a watcher on the taxes array and process changes there? Watchers are used sparingly, with computed properties being much preferred, but they may make sense if you need to be sending data to the backend instead of into the DOM.
The counter prop you registered in your code is not really going to work for the pattern I showed. Generally, props are for parent components to pass data to child components. The preferred pattern when sending data from child to parent is to use $emit. Read more here.

how to use v-model in nested custom components in vue.js?

How can I use v-model for two level deep nested components?
e.g. in HTML
<opening-hr-field v-model="day"> </opening-hr-field>
here day is an object e.g. {is24Open: true, startTime: '5:00 PM'}
JS template
<template type="text/x-template" id="opening-hr-field-template">
<div>
<input type="checkbox" v-model="value.is24Open"> 24 hour
<time-select v-model = "value.startTime"></time-select>
</div>
</template>
<template type="text/x-template" id="time-select-template">
<select :value="value"
v-on:input="$emit('input', $event.target.value)">
<option v-for="t in getHours()">
{{ t }}
</option>
</select>
</template>
Here, I have two level deep v-model. How can I propagate the emit from 2nd template to first template and all way up to the parent? Can you please show me an example?