Add an object to an array of objects vuetify model - javascript

I'm trying to save the value of a radio button dynamically loaded into an array of object. Thoose radios are options for a series of questions of a form, and i would like to get something like:
[{"question1":{
"selected": <id>,
...
},...]
But i don't know how should I define the data or how to reference it wiht the v-model attribute of the radio group.
This is my best try:
<v-radio-group v-model="answers[question.question_id]">
<v-row justify="center">
<v-col v-for="option in question.options" :key="option.option_id">
<v-radio
:label="option.option_text"
:name="question.question_id"
:value="option.option_id"
></v-radio>
</v-col>
</v-row>
</v-radio-group>
And data:
data: () => ({
...
answers: [],
...
}),
What I get rom this is somehting like: [anwswer_id1, anwswer_id1...], witch is close, but not exactly what I need

a simple way could be like this:
<template>
<v-layout column>
<v-radio-group v-model="questions[questionIndex][currentQuestionId].selected">
<v-row justify="center">
<v-col v-for="(option,i) in questions[questionIndex][currentQuestionId].options" :key="i">
<v-radio :label="option.text" :name="currentQuestionId" :value="option._id"></v-radio>
</v-col>
</v-row>
</v-radio-group>
<v-btn #click="handleClickButtonNext">next question</v-btn>
<v-btn #click="handleClickButtonPrev">previous question</v-btn>
</v-layout>
</template>
<script>
export default {
data() {
return {
questions: [
{
question0: {
selected: null,
options: [
{
text: "text 1",
_id: 1
},
{
text: "text 2",
_id: 2
},
{
text: "text 3",
_id: 3
}
]
}
},
{
question1: {
selected: null,
options: [
{
text: "text 2",
_id: 2
},
{
text: "text 3",
_id: 3
},
{
text: "text 4",
_id: 4
}
]
}
},
],
questionIndex: 0
};
},
computed: {
currentQuestionId() {
return "question" + this.questionIndex;
}
},
methods: {
handleClickButtonNext() {
if (this.questionIndex < this.questions.length-1) this.questionIndex++;
},
handleClickButtonPrev() {
if (this.questionIndex > 0) this.questionIndex--;
},
}
};
</script>
where:
questionIndex - keeps track of the current question index
currentQuestionId - gives you the current question id
handleClickButtonNext / handleClickButtonPrev - lets you jump between the questions
This is a way if you just want to show 1 question at a time.
Otherwise, you could also get rid of keeping track of the index, and loop the questions array:
<template>
<v-layout column>
<v-radio-group
v-for="(question, j) in questions"
:key="j"
v-model="question[`question${j}`].selected"
>
<v-row justify="center">
<v-col v-for="(option,i) in question[`question${j}`].options" :key="i">
<v-radio :label="option.text" :name="`question${j}`" :value="option._id"></v-radio>
</v-col>
</v-row>
</v-radio-group>
</v-layout>
</template>
<script>
export default {
data() {
return {
questions: [
{
question0: {
selected: null,
options: [
{
text: "text 1",
_id: 1
},
{
text: "text 2",
_id: 2
},
{
text: "text 3",
_id: 3
}
]
}
},
{
question1: {
selected: null,
options: [
{
text: "text 2",
_id: 2
},
{
text: "text 3",
_id: 3
},
{
text: "text 4",
_id: 4
}
]
}
}
]
};
}
};
</script>

Related

How to return id of a row from v-data-table in VueJs

I'm currently struggling with returning the id of a specific field from each row. I need this id to use it as a parameter for a function that will be used in an action button to delete the row.
This is how my table template is looking like:
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>Publicații</v-toolbar-title>
<v-divider class="mx-4" inset vertical> </v-divider>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Caută"
single-line
clearable
class="shrink"
hide-details=""
></v-text-field>
<v-divider class="mx-4" inset vertical> </v-divider>
<v-btn
color="orange"
v-on:click="
changeRoute();
arataDialogEditare = true;
"
v-show="arataBtnAdaugare"
>{{ txtBtnAdaugaNou }}
</v-btn>
</v-toolbar>
</template>
<template v-slot:[`item.actiuni`]>
<v-btn color="primary" fab x-small elevation="2">
<v-icon>edit</v-icon>
</v-btn>
<v-btn
v-on:click="deletePublication()"
color="primary"
fab
x-small
elevation="2"
>
<v-icon>delete_forever</v-icon>
</v-btn>
</template>
</v-data-table>
</template>
This is how my headers are looking like (my headers is dynamically loaded, that's why I have more than one) :
headers: [],
headersInitial: [
{
text: "Id publicatie",
value: "ID",
},
{
text: "Tip publicație",
value: "tipPublicatie",
},
{
text: "Nume publicație",
value: "titluPublicatie",
},
{
text: "An publicație",
value: "an",
},
{
text: "Actions",
value: "actions",
sortable: false,
},
],
headersFaraTipPublicatii: [
{
text: "Id publicatie",
value: "ID",
},
{
text: "Nume publicație",
value: "titluPublicatie",
},
{
text: "An publicație",
value: "an",
},
{
text: "Actions",
value: "actions",
sortable: false,
},
],
publicatii: [],
publicatiiCuFiltru: [],
This is how I get my data into the table:
initialize() {
this.headers = this.headersInitial;
axios.get("https://localhost:44349/api/items/ReturnarePublicatii").then((returnPub) => {
this.publicatii = returnPub.data;
this.publicatiiCuFiltru = returnPub.data
});
},
Here is my delete function:
deletePublication() {
let ID = this.headersInitial.ID
if (confirm('Are you sure you want to delete the record?')) {
axios.get("https://localhost:44349/api/items/StergereItem/" + ID).then((returnPub) => {
this.publicatii = returnPub.data;
this.publicatiiCuFiltru = returnPub.data
});
}
},
Whenever I try to delete a record, this error occurs: "Uncaught (in promise) Error: Request failed with status code 400". How can I make it work?
let ID = this.headersInitial.ID
this.headersInitial is an array - it has no property ID
Your deletePublication() method needs to receive the id of the row as a parameter (because it can be called for different rows always with different id)
That's why Vuetify passes the actual row into a item slot as a prop. Replace v-slot:item.actiuni with v-slot:item.actiuni="{ item }" as shown in the example. The item is the object (current row) and you can use it in your handler as v-on:click="deletePublication(item.ID)

children is not showing

I have a array with a nested parent-child structure. I need to recursively go through this array and find wanted element. I wrote this function:
component child, this component calls itself, and displays on behalf of each child:
List.vue
<template>
<div>
<div v-for="(item, index) in items" :key="index" >
<div v-if="item.data != null " >
<template v-if="Object.keys(item.data).length > 0">
<template v-for="(item, index) in item.data" >
<v-simple-table :key="index">
<thead>
<tr class="d-flex flex-row">
{{ '░'.repeat(count) }} {{count.length}} {{ item['name'] }}
</tr>
</thead>
<tbody>
</tbody>
</v-simple-table>
</template>
</template>
</div>
<div v-if="item.children != null " >
<template v-if="Object.keys(item.children).length > 0">
<template v-for="(itemD, indexD) in item.children" >
<List :key="indexD" name="List" :items="itemD" :count="count + 1" />
</template>
</template>
</div>
<div v-else></div>
</div>
</div>
</template>
<script>
export default {
name: 'List',
props: {
items: {
type: [Array, Object],
default: [],
},
count: {
type: [Number]
}
},
}
</script>
component parent, this component call component List:
<template>
<div>
<v-row >
<v-col>
<v-card>
<v-card-title>
Estruct
</v-card-title>
<v-row>
<List :items="desserts" :count="count + 1" />
</v-row>
</v-card>
</v-col>
</v-row>
</div>
</template>
<script>
import axios from "axios";
import List from "./List.vue";
export default {
components: { List },
data: (vm) => ({
desserts: [],
count: 0
}),
watch: {
config() {
this.getData();
},
},
methods: {
getData() {
let vm = this;
//
//
axios["get"](process.env.api_url + "/estruct", {
})
.then((response) => {
console.log("response", response.data);
vm.desserts = response.data;
})
.catch((error) => {
console.log(error);
});
},
}
</script>
struct array is like, I am looking at this structure from console.log()
[
{
"data":[{}],
"children":[]
},
{
"data":[
{
"id":64,
"name":"YSVERIS"
}
],
"children":[
{
"data":[
{
"id":85,
"name":"MERCEDES"
}
],
"children":[]
},
{}
]
},
{
"data":[
{
"id":9,
"name":"YUDITH"
}
],
"children":[]
},
{
"data":[
{
"id":10,
"name":"YERNY DEL SOCORRO"
}
],
"children":[]
},
{
"data":[
{
"id":11,
"name":"NIDIA"
}
],
"children":[
{
"data":[
{
"id":21,
"name":"VIVIKEY"
}
],
"children":[]
},
{
"data":[
{
"id":18,
"name":"RODIMIRA "
}
],
"children":[]
}
]
},
{
"data":[],
"children":[]
},
{
"data":[
{
"id":78,
"name":"LUCRECIA"
}
],
"children":[]
},
{
"data":[
{
"id":22,
"name":"DAXI XIOMARA"
}
],
"children":[]
}
]
currently the parent data is being displayed, but not the child data, it should work correct as far as I understand. what do you think??? ....... recursive function is a function that calls itself until it doesn’t. And this technique is called recursion. A recursive function always has a condition to stop calling itself. Otherwise, it will call itself indefinitely. so I don't understand what I'm doing wrong....
I tested in component List.vue, before recursive in <List key="indexD" name="List"....... I added this {{ items }}, so I could see the data object, something like: [ { "data": [ { "id": 85, "name": "MERCEDES"} ] }]
Here is the code in codesandbox code in codesanbox

Vuetify v-select disable options based on object type value

When using Vuetify v-select component and using the prop multiple we can multi select values.
In my example I have several recipes with a parameter type of Breakfast or Dinner.
I want to disable all options for type Breakfast if the user chooses any Dinner recipes, same the other way around.
Here is my codepen if anyone wants to have a go at this: https://codepen.io/5less/pen/eYmaazj
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
selected: [],
recipes: [
{
'id': 1,
'name': 'Pizza',
'type': 'Dinner',
'disabled': false
},
{
'id': 2,
'name': 'Omelet',
'type': 'Breakfast',
'disabled': false
},
{
'id': 3,
'name': 'Scrambled Eggs',
'type': 'Breakfast',
'disabled': false
},
],
}
}
})
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-row align="center">
<v-col cols="12" sm="4">
<v-subheader v-text="'You can only select one type'"></v-subheader>
</v-col>
<v-col cols="12" sm="2">
<v-select
v-model="selected"
:items="recipes"
label="Select"
multiple
hint="Pick your meal"
persistent-hint
item-value="id"
item-text="name"
></v-select>
</v-col>
</v-row>
Selected: {{ selected }}<br>
Recipes: {{ recipes }}
</v-container>
</v-app>
</div>
No need for events or watchers
Vuetify v-select offers the item-disabled prop, which accepts a function that should return true if the item should be disabled and false otherwise.
<template>
<v-select
v-model="selected"
:item-disabled="disableItem"
:items="items"
multiple
/>
</template>
<script>
export default {
data () {
return {
selected: ['name'],
items: [
{
text: 'Nome de A à Z',
value: 'name'
},
{
text: 'Nome de Z à A',
value: '-name'
},
{
text: 'Mais recente à mais antiga',
value: '-updated_at'
},
{
text: 'Mais antiga à mais recente',
value: 'updated_at'
}
]
}
},
methods: {
disableItem (item) {
let invertedValue
if (item.value.match(/^-/)) {
invertedValue = item.value.replace(/^(-)/, '')
} else {
invertedValue = '-' + item.value
}
return this.selected.includes(invertedValue)
}
}
}
</script>
Option 1 - change event handler
Add change event handler for v-select. Like this:
<v-select
#change="onSelect"
v-model="selected"
:items="recipes"
label="Select"
multiple
hint="Pick your meal"
persistent-hint
item-value="id"
item-text="name"
></v-select>
Then in this handler disable all items that have different type:
methods: {
onSelect(e) {
if (e.length == 0) {
this.recipes.forEach((item) => item.disabled = false)
} else {
let chosen = this.recipes.filter((item) => item.id==e[0])
this.recipes.forEach((item) => {
if (item.type != chosen[0].type) {
item.disabled = true
}
})
}
}
}
Option 2 - watcher
Another way is just to add watcher for selected:
watch: {
selected: function (e) {
if (e.length == 0) {
this.recipes.forEach((item) => item.disabled = false)
} else {
let chosen = this.recipes.filter((item) => item.id==e[0])
this.recipes.forEach((item) => {
if (item.type != chosen[0].type) {
item.disabled = true
}
})
}
}
},
Using a watcher on selected array we can check if the selected recipes is of the same type:
watch: {
selected: function() {
for (const i in this.recipes) {
if (this.selected.length && this.recipes[i].type != this.recipes[this.recipes.findIndex(x => x.id === this.selected[0])].type) {
this.recipes[i].disabled = true;
} else {
this.recipes[i].disabled = false;
}
}
}
}

How to get current item index in v-carousel?

I have the following code that cycles a carousel which is fine but I want to be able to display the item title underneath as appose to on top of the image. I figured the way to do this is to create a new data value that is updated each time the carousel changes. I cannot figure out how to do this however.
<v-carousel>
<v-carousel-item
v-for="(item,i) in servicesCarouselItems"
:key="i"
:src="item.src"
>
</v-carousel-item>
</v-carousel>
<v-card-title class="justify-center">{{currentTitle}}</v-card-title>
<script>
export default {
data: () => ({
currentTitle: '',
servicesCarouselItems: [
{
name: "Title1",
src: require('../../1.jpeg'),
},
{
name: "Title2",
src: require('../../2.jpeg'),
},
{
name: "Title3",
src: require('../../3.jpeg'),
}
],
})
}
</script>
Propably best way is to use v-model - index of current item is exposed there...
<v-carousel v-model="currentIndex">
<v-carousel-item
v-for="(item,i) in servicesCarouselItems"
:key="i"
:src="item.src"
>
</v-carousel-item>
</v-carousel>
<v-card-title class="justify-center">{{ currentTitle }}</v-card-title>
<script>
export default {
data: () => ({
currentIndex: 0,
servicesCarouselItems: [
{
name: "Title1",
src: require('../../1.jpeg'),
},
{
name: "Title2",
src: require('../../2.jpeg'),
},
{
name: "Title3",
src: require('../../3.jpeg'),
}
],
}),
computed: {
currentTitle() {
return this.servicesCarouselItems[this.currentIndex].name
}
}
}
</script>
I managed to solve this issue by using the v-on:change / #change Vue event as shown in the example below.
<v-carousel #change="currentTitle = servicesCarouselItems[$event].name">
<v-carousel-item
v-for="(item,i) in servicesCarouselItems"
:key="i"
:src="item.src"
>
</v-carousel-item>
</v-carousel>
Further reading for those interested:
https://renatello.com/get-selected-value-on-change-in-vuejs/#The_advantages_of_using_change_event_instead_of_v-model_binding

vuetify treeview every objects was opened, but i did not set "open-all" option

i'm setting up vuetify's treeview component for my project.
i clicked treeview's folder objects, every objects opened.
but i did not set 'open-all' option.
my project is based vue cli 3 and my ESLint configs is 'airbnb'.
TEMPLATE :
<v-card class="mx-auto">
<v-sheet class="pa-1 tree__resources lighten-2">
<v-treeview
:active.sync="active"
:open.sync="open"
:items="items"
item-key="id"
activatable
active-class="primary--text"
open-on-click
return-object>
<template v-slot:prepend="{ item, open }">
<v-icon v-if="item.type == 'directory'">
{{ open ? 'mdi-folder-open' : 'mdi-folder' }}
</v-icon>
<v-icon v-else>
{{ files[item.type] }}
</v-icon>
</template>
</v-treeview>
</v-sheet>
</v-card>
Scripts :
export default {
data: () => ({
active: [],
open: [],
items: ["JSON DATA"],
files: {
html: 'mdi-language-html5',
js: 'mdi-nodejs',
json: 'mdi-json',
md: 'mdi-markdown',
pdf: 'mdi-file-pdf',
png: 'mdi-file-image',
txt: 'mdi-file-document-outline',
jpg: 'mdi-file-image',
jpeg: 'mdi-file-image',
gif: 'mdi-file-image',
arsc: 'mdi-file-document',
RSA: 'mdi-key-variant',
SF: 'mdi-file-document',
MF: 'mdi-file-document',
xml: 'mdi-file-xml',
dex: 'mdi-android',
java: 'mdi-code-braces',
kt: 'mdi-android',
css: 'mdi-language-css3',
android: 'mdi-android',
properties: 'mdi-file-document',
version: 'mdi-file-document',
so: 'mdi-file-document',
provider: 'mdi-file-document',
providers: 'mdi-file-document',
},
filename: '',
filepath: '',
filetype: '',
},
}),
computed: {
selected() {
if( !this.active.length ) return undefined;
const selected = this.active[0];
console.log(selected);
},
},
methods: {
.
.
.
JSON DATA SAMPLE :
[
{
"name":"sources",
"type":"directory",
"children":[
{
"name":"android",
"type":"directory",
"children":[
{
"name":"support",
"type":"directory",
"children":[
{
"name":"fragment",
"type":"directory",
"children":[
{
"name":"R.java",
"id":662,
"type":"java",
"path":"sources/android/support/fragment/R.java"
},
{
"name":"BuildConfig.java",
"id":663,
"type":"java",
"path":"sources/android/support/fragment/BuildConfig.java"
}
]
},
{
"name":"mediacompat",
"type":"directory",
"children":[
{
"name":"R.java",
"id":664,
"type":"java",
"path":"sources/android/support/mediacompat/R.java"
},
{
"name":"BuildConfig.java",
"id":665,
"type":"java",
"path":"sources/android/support/mediacompat/BuildConfig.java"
}
]
}
]
}
]
},
{
"name":"ntouch",
"type":"directory",
"children":[
{
"name":"ntouch_apk_01",
"type":"directory",
"children":[
{
"name":"R.java",
"id":666,
"type":"java",
"path":"sources/ntouch/ntouch_apk_01/R.java"
},
{
"name":"BuildConfig.java",
"id":667,
"type":"java",
"path":"sources/ntouch/ntouch_apk_01/BuildConfig.java"
},
{
"name":"Ntouch_apk_01.java",
"id":668,
"type":"java",
"path":"sources/ntouch/ntouch_apk_01/Ntouch_apk_01.java"
},
{
"name":"SendDateToServer.java",
"id":669,
"type":"java",
"path":"sources/ntouch/ntouch_apk_01/SendDateToServer.java"
}
]
}
]
}
]
},
{
"name":"resources",
"type":"directory",
"children":[
{
"name":"META-INF",
"type":"directory",
"children":[
{
"name":"MANIFEST.MF",
"id":670,
"type":"MF",
"path":"resources/META-INF/MANIFEST.MF"
},
{
"name":"CERT.RSA",
"id":671,
"type":"RSA",
"path":"resources/META-INF/CERT.RSA"
},
{
"name":"CERT.SF",
"id":672,
"type":"SF",
"path":"resources/META-INF/CERT.SF"
}
]
},
{
"name":"classes.dex",
"id":673,
"type":"dex",
"path":"resources/classes.dex"
},
{
"name":"AndroidManifest.xml",
"id":674,
"type":"xml",
"path":"resources/AndroidManifest.xml"
},
]
}
]
when i clicked "resources" folder object, expect the output this:
https://imgur.com/OjU4hjx
but the actual output this: EVERYTHING OPEN IMMEDIATELY
https://imgur.com/7ytQ3mX
Your item-key is id, which is undefined in some node. You should have id for each node includes parent node, something like:
[
{
"name":"sources",
"id": 1,
"type":"directory",
"children":[
{
"name":"android",
"id": 2
"type":"directory",
"children":[]
}
....
}
]
or change item-key to name. I expected name is unique in your structure (which might not be possible)
<v-treeview
:active.sync="active"
:open.sync="open"
:items="items"
item-key="name"
activatable
active-class="primary--text"
open-on-click
return-object>
<template v-slot:prepend="{ item, open }">
<v-icon v-if="item.type == 'directory'">
{{ open ? 'mdi-folder-open' : 'mdi-folder' }}
</v-icon>
<v-icon v-else>
{{ files[item.type] }}
</v-icon>
</template>
</v-treeview>

Categories