Duplicate a select element and dynamically add v-model - vue.js

I want to duplicate a select element with the same values after a button click event. What is the best way to dynamically add a model for this duplicate so that the selected data keeps its 2-way binding? Also, when using a v-model will cause the first option not to be visible.
<section id="app">
selected jobs: {{preferredJobs.selectedJobs}}
<br><br>
<div class="form-row">
<div class="col-12">
<div class="form-group" v-for="(jobs, index) in preferredJobs.jobs">
<label for="preferred_function" v-if="index == 0">
Preferred job (multiple values possible) <br><br>
</label>
<select v-model="preferredJobs.selectedJobs">
<option value="">-- select --</option>
<option v-for="jobFunction in allJobs" :value="jobFunction.value">{{jobFunction.label}}</option>
</select>
<br><br>
</div>
</div>
</div>
<div class="form-row">
<div class="col-6">
<button type="button" #click="preferredJobs.jobs.push({jobs: allJobs})" class="btn btn-plus"><i class="fas fa-plus-circle"></i> Add Job</button>
</div>
<div class="col-6" v-if="itemsLength(preferredJobs.jobs) > 1">
<br>
<button type="button" #click="preferredJobs.jobs.pop()" class="btn btn-minus"><i class="fas fa-minus-circle"></i> Remove Job</button>
</div>
</div>
<script>
new Vue({
el: "#app",
data() {
return {
allJobs: [
{ value: 'job1', label: 'Job 1' },
{ value: 'job2', label: 'Job 2' },
{ value: 'job3', label: 'Job 3' },
{ value: 'job4', label: 'Job 4' },
{ value: 'job5', label: 'Job 5' },
],
preferredJobs: {
selectedJobs: [],
jobs: [
{
jobs: this.allJobs
},
],
},
}
},
methods: {
itemsLength(items){
return items.length;
},
},
})

You can do something like
v-model="data[dynamic_index]"
or you can use
<input :value="some_dynamic_variable" #input="$emit('input', $event.target.value)>

Related

422 (Unprocessable Entity) with axios.put and using props in vue js 3

I have tried to use props to pass data across components but I have problem with select option, how can I put the value is role.id into updateUser() function using axios.put without error 422
Modals.vue
<div class="modal modal-black fade" id="userEditModal">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">
Edit user
<strong class="text-primary">{{ name }} - {{ username }}</strong>
</h4>
<button type="button" data-dismiss="modal">
<i class="tim-icons icon-simple-remove"></i>
</button>
</div>
<form class="form-horizontal">
<div class="modal-body">
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Username</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="username"
v-model.lazy="username" />
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Name</label>
<div class="col-md-9">
<input
type="text"
class="form-control"
name="username"
v-model.lazy="name" />
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Email</label>
<div class="col-md-9">
<input
type="email"
name="email"
class="form-control"
v-model.lazy="email" />
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Roles</label>
<div class="col-md-9">
<div class="form-group">
<select v-model="roleSelected" name="roles">
<option
v-for="role in roles"
:key="role.index"
:value="role.id">
{{ role.name }}
</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer d-flex flex-row">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button type="button" class="btn btn-primary" #click="updateBtn()">
Save
</button>
</div>
</form>
</div>
</div>
</div>
<script>
export default {
name: "Modals",
props: ["name", "username", "email", "roles"],
data() {
return {
roleSelected: "",
};
},
emits: ["trigger"],
methods: {
updateBtn() {
this.$emit("trigger", "");
},
},
};
</script>
ManageUsers
<Modals
:name="userInfo.name"
:username="userInfo.username"
:email="userInfo.email"
:roles="roles"
#trigger="updateUser()"
/>
<script>
import axios from "axios";
import Modals from "/src/components/cores/Modals.vue";
export default {
name: "manageUsers",
components: { Modals },
data() {
return {
users: [],
roles: [],
hidden: false,
index: 0,
newUser: {
name: null,
username: null,
email: null,
password: null,
confirmPassword: null,
roles: null,
},
userInfo: {
uuid: "",
name: "",
username: "",
phone: "",
email: "",
role: "",
},
};
},
methods: {
getRoles() {
axios.get(`/roles/listRoles`).then((res) => {
this.roles = res.data.data;
});
},
refreshUsers() {
axios.get(`/users/allusers`).then((res) => {
this.users = res.data.data;
});
},
addUser() {
axios
.post(`/users/create`, this.newUser);
},
getUserInfo(user) {
axios
.get(`/users/show/${user.uuid}`)
.then((res) => {
this.userInfo.uuid = res.data.data.uuid;
this.userInfo.name = res.data.data.name;
this.userInfo.email = res.data.data.email;
this.userInfo.username = res.data.data.username;
this.userInfo.phone = res.data.data.phone;
});
},
updateUser() {
axios
.put(`/users/update/${this.userInfo.uuid}`, {
name: this.userInfo.name,
username: this.userInfo.username,
email: this.userInfo.email,
roles: this.roleSelected,
})
.then((res) => {
this.refreshUsers();
})
},
},
mounted() {
this.getRoles();
this.refreshUsers();
},
};
</script>
Roles list data
{
"success": true,
"data": [
{
"id": 1,
"name": "Master",
},
{
"id": 2,
"name": "Manager",
},
]
}
User Info
{
"success": true,
"data": {
"uuid": "5ebc3892-49b7-4468-81e4-aaf1742d3dff",
"name": "John Doe",
"email": "johndoe#gmail.com",
"username": "johnjohn",
},
}

Cloning div with vue

<template>
<b-form #submit.prevent="Submit" class="mb-5">
<div class="inputArea" v-for="input in inputs" :key="input.id">
<b-form-group label-cols-sm="2" label="Solution (EN)">
<ckeditor :editor="ckeditor" v-model="form.body.en" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.en']">
<div v-for="err in errors['body.en']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (FR)">
<ckeditor :editor="ckeditor" v-model="form.body.np" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.np']">
<div v-for="err in errors['body.np']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (IT)">
<ckeditor :editor="ckeditor" v-model="form.body.in" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.in']">
<div v-for="err in errors['body.in']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
</div>
<b-form-group label="" label-cols-sm="2">
<b-button type="button" class="text-white" variant="dark" #click="addRow">Add row</b-button>
</b-form-group>
<b-form-group label="" label-cols-sm="2">
<b-button type="submit" class="text-white" variant="dark">Submit</b-button>
</b-form-group>
</b-form>
</template>
<style lang="scss">
</style>
<script>
import CKEditor from '#ckeditor/ckeditor5-vue2'
import ClassicEditor from '#ckeditor/ckeditor5-build-classic'
export default {
name: 'Interaction',
components: {
ckeditor: CKEditor.component
},
data(){
return{
counter: 0,
inputs: [
{
en: '',
np: '',
in: '',
}],
form: {
body: [
{
en: '',
np: '',
in: '',
}
],
},
errors: {},
ckeditorData: '<p></p>',
ckeditorConfig: {
// The configuration of the editor
},
ckeditor: ClassicEditor
}
},
methods: {
Submit(){
this.storing = true
this.errors = {}
var self = this
axios.post('/this-is-a-post-url', this.form)
.then(function(response){
console.log(response)
})
},
addRow() {
this.inputs.push({
en: '',
it: '',
fr: '',
id: `${++this.counter}`,
value: '',
});
}
}
}
</script>
I will have array coming in the body name so I am trying to to clone the clone body on a click of a button which has a function AddRow. I want to clone the three fields en,np,in and I want it work like normal html works in this. Example when we clone html form it create input field like so <input name="body['en'][0]"> and when we clone another time it creates something like this <input name="body['en'][1]">.
I have the above code, it clones the body but it also clones the added text before cloning. I want to add an empty field while cloning and also want to update v-model. How can I do that?
Refer below example:
https://codepen.io/telen/pen/OeNZVV
<main class="container">
<form id="app" data-apartments='[{ "price": "23000", "rooms": "12" }, { "price": "42000", "rooms": "32" }]'>
<h1>
Dynamic apartment forms
</h1>
<hr>
<div class="row">
<div class="col-xs-2">
<button type="button" v-on:click="addNewApartment" class="btn btn-block btn-success">
Add +
</button>
</div>
<div class="col-xs-10">
Would you like add more apartments?
</div>
</div>
<div v-for="(apartment, index) in apartments">
<div class="row">
<div class="col-xs-2">
<label> </label>
<button type="button" v-on:click="removeApartment(index)" class="btn btn-block btn-danger">
Rem -
</button>
</div>
<div class="form-group col-xs-5">
<label>Price (HUF)</label>
<input v-model="apartment.price" type="number"
name="apartments[][price]" class="form-control" placeholder="Price">
</div>
<div class="form-group col-xs-5">
<label>Rooms (PCS)</label>
<input v-model="apartment.rooms" type="number"
name="apartments[][rooms]" class="form-control" placeholder="Rooms">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<button type="submit" v-on:click.prevent="sumbitForm" class="btn btn-block btn-primary">
Submit
</button>
</div>
<div class="col-xs-10">
Open the console (F12) and see the result
</div>
</div>
<hr>
<pre>{{ $data }}</pre>
</form>
JS:
window.app = new Vue({
el: '#app',
data: {
apartment: {
price: '',
rooms: ''
},
apartments: [],
},
mounted: function () {
/*
* The "data-apartments" could come from serverside (already saved apartments)
*/
this.apartments = JSON.parse(this.$el.dataset.apartments)
},
methods: {
addNewApartment: function () {
this.apartments.push(Vue.util.extend({}, this.apartment))
},
removeApartment: function (index) {
Vue.delete(this.apartments, index);
},
sumbitForm: function () {
/*
* You can remove or replace the "submitForm" method.
* Remove: if you handle form sumission on server side.
* Replace: for example you need an AJAX submission.
*/
console.info('<< Form Submitted >>')
console.info('Vue.js apartments object:', this.apartments)
window.testSumbit()
}
}
})
/*
* This is not Vue.js code, just a bit of jQuery to test what data would be submitted.
*/
window.testSumbit = function () {
if (!window.jQuery) {
console.warn('jQuery not present!')
return false
}
console.info('Submitted (serverside) array:', jQuery('form').serializeJSON())
}

Local-Storage in Vue.JS

I am working on Vue.JS and I tried to use local-storage with it to save data. In my code, I can store and retrieve all data with local-storage except line-through effect. Here, I am trying to store actual boolean value of line-through effect in local-storage and want to retrieve that value on to-do list app.
<title>To Do List</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>
<style>
.taskDone {
text-decoration: line-through;
}
</style>
</head>
<body>
<div id="todo-list" class="container">
<div class="container col-sm-8 col-sm-offset-2">
<h1 class="text-center"> <big><b> To Do List </b> </big></h1>
<h5 class="text-center"> <span v-show="itemsTodo.length"> ({{ itemsTodo.length }} pending) </span></h5>
<div class="col-md-8">
<button v-if="state === 'default'" class="btn btn-primary" #click="changeState('edit') ">Add Item</button>
<button v-else class="btn btn-info" #click="changeState('default')">Cancel</button>
</div>
<br>
<br>
<div v-if="state === 'edit'" >
<div class="col-sm-4">
<input class='form-control' v-model="newItem" type="text" placeholder="Type here" #keyup.enter="saveItem" >
</div>
<div class="col-sm-4">
<input class="form-control" v-model="newdate" type="date" type="text"/>
</div>
<div class="col-sm-4">
<button class='btn btn-primary btn-block' v-bind:disabled="newItem.length === 0"#click= "saveItem">Save Item</button>
</div>
</div>
<br>
<br>
<ul type="none" class="list-group">
<li class="list-group-item" v-for="(item,index,date) in items" :class="{taskDone : item.completed}" >
<h4>
<input type="checkbox" v-model="item.completed" #click="item.completed = !item.completed">
<button class="btn btn-primary " #click.stop="removeitems(index)">× </button>
<b><i> {{ item.label }} {{ item.date }} </i></b></h4>
</li>
</ul>
<h2 v-if="items.length === 0">Nice Job! Nothing in TO DO LIST</h2>
<div class="col-sm-4">
<button class="btn btn-warning btn-block" #click="clearcompleted"> Clear Completed</button>
</div>
<div class="col-sm-4">
<button class="btn btn-danger btn-block" #click="clearAll"> Clear All</button>
</div>
</div>
</div>
2. Vue.JS code
<script src="https://unpkg.com/vue" ></script>
<script>
var todolist = new Vue({
el: '#todo-list',
data : {
state : 'edit',
header: 'To Do List',
newItem: '',
newdate: '',
items: [
{
label:'coffee',
completed:false,
date:'2019-06-20' ,
},
{
label:'tea',
completed:false,
date:'2019-06-19' ,
},
{
label:'milk',
completed:false,
date:'2019-06-19' ,
},
]
},
computed:{
itemsDone(){
return this.items.filter(items => items.completed)
},
itemsTodo(){
return this.items.filter(items =>! items.completed)
},
},
methods:{
saveItem: function(){
if (this.newItem != ''){
this.items.push({
label:this.newItem,
completed: false,
date : this.newdate,
});
this.newItem = '';
this.newdate = '';
}},
changeState: function(newState){
this.state = newState;
this.newItem = '';
this.newdate = '';
},
removeitems(index){
this.items.splice(index,1);
},
clearcompleted (){
this.items = this.itemsTodo;
},
clearAll: function(){
this.items = [ ];
},
},
mounted(){
console.log('App Mounted!');
if (localStorage.getItem('items')) this.items = JSON.parse(localStorage.getItem('items'));
},
watch: {
items:{
handler(){
localStorage.setItem('items',JSON.stringify(this.items));
},
},
},
});
</script>
I expect correct boolean value of line-through effect to be stored in local-storage. So that, appropriate effect will show on browser.
You are just watching items. If you change something in a item (in your case completed) the handler will not be called and your change is not stored.
You could use a "deep" watcher but i suggest to call your save logic whenever you changed something.

Not getting correct value from click method

I am trying to get the value from a data controlled by v-model within a component.
The data changes in the app and in Vue dev tools but if I console log that data I always get the previous value.
Vue App
Here is the data I'm passing to the components
new Vue({
el: "#app",
data: {
"children": {
"haveAnyOtherDependents": 'yes',
"havePets": 'no',
},
},
})
Vue Component
Here I pass the data I need from the app
// button-group component
Vue.component('button-group', {
props: {
title: {
type: String
},
name: {
type: String
},
content: {
type: String
},
dataSource: {
type: String
}
},
data: function () {
return {
myTitle: this.title,
myName: this.name,
myContent: ''
}
},
created(){
this.myContent = this.setMyContent
},
methods: {
sendData: function(){
console.log('data: ', this.myContent, 'source', this.dataSource);
}
},
computed: {
setMyContent: function(){
return this.content
}
},
template: `
<div class="form-group row mb-1">
<br>
<div class="col-sm-6 pt-1 text-md" v-text="myTitle + ' = ' + myContent"></div>
<div class="col-sm-6 text-right">
<div class="btn-group m-0">
<label class="btn mr-05 p-0 rounded-left">
<input type="radio" :name="myName" value="no" v-model="myContent" #click="sendData()">
<span class="d-block p-1 px-3 text-sm rounded-left">
<i class="fas fa-check mr-1 text-xs"></i>No
</span>
</label>
<label class="btn p-0 rounded-right">
<input type="radio" :name="myName" value="yes" v-model="myContent" #click="sendData()">
<span class="d-block p-1 px-3 text-sm rounded-right">
<i class="fas fa-check mr-1 text-xs"></i>Yes
</span>
</label>
<label class="d-none btn p-0">
<input class="d-none" type="radio" :name="myName" value="unknown" v-model="myContent" #click="sendData()" checked>
<span class="d-block p-1 px-3 text-sm">
<i class="fas fa-check d-none mr-1 text-xs"></i>Unknown
</span>
</label>
</div>
</div>
</div>
`
});
// end button-group
HTML
<div id="app" class="container">
<button-group title="Other Dependants" name="other_dependents"
:content="children.haveAnyOtherDependents" data-source="children.haveAnyOtherDependents"></button-group>
<button-group title="Pets" name="pets" :content="children.havePets" data-source="children.havePets"></button-group>
</div>
Here is a fiddle, https://jsfiddle.net/yktoL8oz/
As answered in the comments by #Bert
The click event fires before the model is updated. Use a different event like change"
I changed the #click="sendData()" to #change="sendData()" and that solved the issue.

VueJs: Dynamically building form inputs and IDs within a list

I am building a list using VueJs by adding list-items through a form. I want to also add notes to be sub-items of the main list items. I can add the major list items with no problems:
When I try to add subitems all the input fields for the subitems respond to the data I am keying in before I press the add button for the first time. I am guessing that this has to do how with how I dynamically assigning Ids to the inputs. And after I press the submit button it doesn't add the note to the list of subitems. I can't seem to figure out why:
I include a JsFiddle
html
<div id="app">
<form v-on:submit.prevent="addInstance()">
<div class="form-group">
<input id="eventtext" type="text" class="form-control" placeholder="Enter new Instance" v-model="todo.name">
<button><i class="fa fa-plus"> Add Instance</i></button>
</div>
</form>
<div class="">
<div v-for="todo in todoStore" class="list-group">
<div class="list-group-item">
<h4>
Main Card
</h4> {{todo.name}}
</div>
<div class="list-group-item nopadding">
<button class="btn btn-xs btn-danger margin-10" v-on:click="todoDelete(todo)">
<i class=" fa fa-trash"></i>
</button>
</div>
<div v-for="note in todoNoteStore" class="list-group nopadding nomargin">
<div v-if="todo.id == note.card_id">
<div class="list-group-item">
<h4>
Note fore card {{todo.id}}
</h4> {{note.card_id}}
</div>
<div class="list-group-item nopadding">
<button class="btn btn-xs btn-danger margin-10" v-on:click="removeNoteInstance(note)">
<i class=" fa fa-trash"></i>
</button>
<form v-on:submit.prevent="addNoteInstance()">
<div class="form-group">
<input id="noteCount=noteCount+1" type="text" class="form-control"
placeholder="Enter new Note Instance" v-model="todoNote.name">
<button><i class="fa fa-plus"> Add Note Instance</i></button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Js
new Vue({
el: '#app',
data: function() {
return {
todo: {
id: 1,
name: '',
completed: false,
check: ''
},
todoNote: {
id: 1,
name: '',
completed: false,
check: ''
},
todoStore: [{
id: 1,
name: 'White',
completed: true,
check: 'This is from card 1'
},
{
id: 2,
name: 'Balack',
completed: true,
check: 'This is from card 2'
}
],
todoNoteStore: [{
id: 1,
card_id: 2,
name: 'White',
event3: 'Heisenberg',
completed: true,
check: 'This is from note 1'
},
{
id: 2,
card_id: 1,
name: 'Yelloe',
event3: 'Green',
completed: true,
check: 'This is from note 2'
}
]
}
},
methods: {
addInstance: function() {
this.todoStore.push(this.todo);
this.todo = {};
},
addNoteInstance: function() {
this.todoNoteStore.push(this.todoNote);
this.todoNote = {};
},
removeNoteInstance: function(note) {
this.todoNoteStore.remove(note);
}
}
});
css
.nopadding {
padding-top: 0px;
!important;
padding-bottom: 0px;
!important;
}
.nomargin {
margin: 0px;
}