VueJS: Dynamic props based on v-select item - javascript

I have got a chart which uses properties.
<template>
<v-row>
<v-col col="12" sm="12">
<Chart :data="series2"></Chart> ### This chart receives the props
</v-col>
<v-col cols="12" sm="6">
<v-select
item-color="red"
item-text="muh"
v-model="e7"
:items="items"
label="Select"
single
chips
hint="Which series do you want?"
persistent-hint
></v-select>
</v-col>
</v-row>
</template>
This is my script with the series.
<script>
import Chart from "./Chart"
export default {
data: function () {
return {
e7: [],
series1: [1,2,3,4,5],
series2: [5,6,5,6,5],
series3: [5,4,3,2,1],
items: ["series1", "series2", "series3"]
}
},
components: {
Chart
},
}
</script>
Passing the props works fine, but I want the v-select to change the selected series (props) based on the selected item. How can I do this?

You can do something like this.
<Chart :data="$data[e7]"></Chart>
Where e7 is the v-model attribute for v-select.

Related

Vue.js: How can I put a Login Modal inside a dropdown Menu?

I have the following dropdown menu:
<template>
<v-menu close-on-click transition="slide-y-transition">
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" v-bind="attrs" v-on="on">
Menu
</v-btn>
</template>
<v-list>
<v-list-item v-for="(item, index) in menuItemsMisc" :key="index" v-model="item.model">
<v-list-item-title>
<v-btn block color="white" #click="item.fn">{{ item.title }}</v-btn>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<!-- Modal code here -->
</template>
<script>
export default {
name: 'MenuBar',
data: () => ({
loginModal: false,
purchaseModal: false,
menuItemsMisc: [
{ title: 'Login',
model: 'loginModal',
fn: () => { this.loginModal = true}
},
{ title: 'Purchase',
model: 'purchaseModal',
fn: () => { this.purchaseModal = true }
},
]
}),
}
</script>
And I am trying to display this Login Modal When the Login Button is clicked in the dropdown.
<v-dialog v-model="loginModal" persistent max-width="500px">
<v-card class="elevation-12">
<v-toolbar color="primary" dark flat>
<v-toolbar-title>Login form</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text>
<v-form>
<v-text-field name="login" prepend-icon="mdi-account" type="text"></v-text-field>
<v-text-field id="password" name="password" prepend-icon="mdi-lock" type="password">
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary">Login</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
But whenever I click the Login or Purchase Button, I have an error that says:
TypeError: Cannot set property 'loginModal' of undefined
What is the Problem here?
From the Vue docs on v-model:
You can use the v-model directive to create two-way data bindings on form input, textarea, and select elements. It automatically picks the correct way to update the element based on the input type.
The v-model property on your <v-dialog> component is expecting it to be an input of some type.
You should be able to simply change this to a v-if:
<v-dialog v-if="loginModal" persistent max-width="500px">
This will cause the <v-dialog> component to display when your button is clicked.
EDIT: Please also make sure your data property on the Vue instance is declared as a class-style function. If you use a lambda function you will lose the this scope when referring to this.loginModal:
export default {
...
data() {
return {
...
}
}
}

Display Vuetify cards in a single row instead of a column?

I am using Vuetify 1.5 and Vuetify grid system to set up my layout. Now i have a component HelloWorld which i am importing into my Parent Component. I have set up the layout in my HelloWorld and i am trying to display my cards in a single row instead having all of them show up in a column. I am not sure what i am doing wrong here.
I have setup the <v-layout align-center justify-center row fill-height class="mt-5"> which should render it in one row.
Check out this working CodeSandbox.
I am not adding my Vuex store below since the problem is in the layout and not the data itself. The store is minimal and is in the link above.
This is my HellWorld Component:-
<template>
<v-layout align-center justify-center row fill-height class="mt-5">
<v-flex xs4>
<v-card class="mx-4">
<v-img :src="src"></v-img>
<v-card-title primary-title>
<div>{{title}}</div>
</v-card-title>
</v-card>
</v-flex>
</v-layout>
</template>
<script>
export default {
name: "HelloWorld",
props: {
title: String,
src: String,
id: Number
},
data() {
return {};
}
};
</script>
And this is my Parent component:-
<template>
<v-container>
<v-layout align-center justify-center row fill-height class="mt-5">
<h2>Parent Component</h2>
</v-layout>
<draggable v-model="draggableCards">
<template v-for="(tech,i) in getCardArray">
<HelloWorld :src="tech.src" :title="tech.title" :key="i"/>
</template>
</draggable>
</v-container>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
import HelloWorld from "./HelloWorld";
import draggable from "vuedraggable";
export default {
components: {
draggable,
HelloWorld
},
computed: {
...mapGetters({
getCardArray: "getCardArray"
}),
draggableCards: {
get() {
return this.$store.state.cardArray;
},
set(val) {
this.$store.commit("setCardArray", val);
}
}
},
methods: {
...mapMutations({
setCardArray: "setCardArray"
})
}
};
</script>
Basically i am trying to show the cards in a row instead of a column. Any help will be appreciated. Thank you :).
You are looping through <v-layout> this means you are creating a new line (layout) for each card. You need to take the layout out of the loop put in the parent and they will be more than one on one row.
Something like:
<draggable v-model="draggableCards">
<v-layout>
<template v-for="(tech,i) in getCardArray">
<HelloWorld :src="tech.src" :title="tech.title" :key="i"/>
</template>
</v-layout>
</draggable>
And remove from HelloWorld

Vuetify open select/autocomplete/combobox menu on focus

I have a Vuetifyjs Autocomplete. I want to open its menu when user focuses on it using tab key from previous input. Below is the sample code
<div id="app">
<v-app>
<v-container >
<v-row >
<v-col cols="12" md="4">
<v-text-field label="Text Field"/>
</v-col>
<v-col cols="12" md="6">
<v-autocomplete
label="Autocomplete"
:items="components"
hint="need to open menu on focus, just like click" persistent-hint
></v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
<script>
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
components: [
'Autocompletes', 'Comboboxes', 'Forms', 'Inputs', 'Overflow Buttons', 'Selects', 'Selection Controls', 'Sliders', 'Textareas', 'Text Fields',
],
},
methods: {
}
})
</script>
I have also created a pen for this https://codepen.io/salalaslam/pen/YzzPajN
Because vuetify does not have the option you want, you must control it directly.
An input tag exists inside the autocomplete component. Specify focus event directly on this input tag.
Try this.
// template
<v-autocomplete
ref="autocomplete"
label="Autocomplete"
:items="components"
hint="need to open menu on focus, just like click"
persistent-hint
></v-autocomplete>
export default {
mounted () {
let autocompleteInput = this.$refs.autocomplete.$refs.input
autocompleteInput.addEventListener('focus', this.onFocus, true)
},
methods: {
onFocus (e) {
this.$refs.autocomplete.isMenuActive = true // open item list
}
}
}
pen - https://codepen.io/kdydesign/pen/rNNadXN?editors=1111
Instead of digging to the low-level DOM, you can simply use Vue.js's focus() and activateMenu()
<template>
<v-row>
<v-col cols="12" md="4">
<v-text-field label="Text Field" #keydown.tab="focus" />
</v-col>
<v-col cols="12" md="6">
<v-autocomplete
ref="aut"
label="Autocomplete"
:items="components"
hint="need to open menu on focus, just like click"
persistent-hint
></v-autocomplete>
</v-col>
</v-row>
</template>
<script>
export default {
layout: "center-six",
data() {
return {
components: ["A", "B", "C", "D"],
};
},
methods: {
focus() {
this.$refs["aut"].focus();
this.$refs["aut"].activateMenu();
},
},
};
</script>
I have also created a simple codePen VueJs Menu Activator

How to add an icon in front of every VuetifyJS combobox entry?

I'm using the combobox component of VuetifyJS and I need to add an icon in front of every entry in the drop down. How to do that?
Here is a CodePen example of the combobox: https://codepen.io/anon/pen/KBLXYO
HTML
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-layout wrap>
<v-flex xs12>
<v-combobox
v-model="select"
:items="items"
label="Select a favorite activity or create a new one"
></v-combobox>
</v-flex>
</v-layout>
</v-container>
</v-app>
</div>
JS:
new Vue({
el: '#app',
data () {
return {
select: 'Programming',
items: [
'Programming',
'Design',
'Vue',
'Vuetify'
]
}
}
})
Use the item scoped slot.
<v-combobox
v-model="select"
:items="items"
label="Select a favorite activity or create a new one">
<template slot="item" slot-scope="data">
<v-icon>home</v-icon> {{data.item}}
</template>
</v-combobox>
Here is your pen updated.
FWIW, this is all covered in the documentation.

Programmatically create forms in vue

I want to ask the user how many points he wants to create and then get each points coordinates.
I tried creating a initial text field to get how many points and then a loop to create each form. It works but I don't know how to get each form value.
How can I get each form values? Or is there a better way to do it?
<template>
<div>
<v-card class="mb-3">
<v-card-text>
<v-text-field label="How many nodes" :value="nodes" #input="onInput" type="number"></v-text-field>
</v-card-text>
</v-card>
<v-container fluid grid-list-md>
<v-layout row wrap>
<template v-for="i in nodes">
<v-flex :key="i" xs12 md3>
<div>
<v-card class="mb-3">
<v-card-text>
<div>Node {{i}}</div>
<v-text-field label="Coord X" value="x1" #input="getValues" type="number" v-model="no1"></v-text-field>
<v-text-field label="Coord Y" :value="y1" #input="getValues" type="number"></v-text-field>
</v-card-text>
</v-card>
</div>
</v-flex>
</template>
</v-layout>
</v-container>
</div>
</template>
<script>
export default {
data () {
return {
nodes: 2
}
},
methods: {
onInput (val) {
this.nodes = parseInt(val)
}
}
}
</script>
I think this would be a better way of doing it:
<template>
<div>
<v-card class="mb-3">
<v-card-text>
<v-text-field label="How many nodes" v-model="nodes" type="number"></v-text-field>
</v-card-text>
</v-card>
<v-container fluid grid-list-md>
<v-layout row wrap>
<template v-for="(node, index) in nodesArr">
<v-flex :key="i" xs12 md3>
<div>
<v-card class="mb-3">
<v-card-text>
<div>Node {{index + 1}}</div>
<v-text-field label="Coord X" v-model="node[index].coordX" type="number" v-model="no1"></v-text-field>
<v-text-field label="Coord Y" v-model="node[index].coordY" type="number"></v-text-field>
</v-card-text>
</v-card>
</div>
</v-flex>
</template>
</v-layout>
</v-container>
</div>
</template>
<script>
export default {
data () {
return {
nodes: 0,
nodesArr: []
}
},
watch: {
nodes(newVal) {
this.nodesArr = [];
for(var i=0; i<this.nodes; i++){
this.nodesArr.push({coordX: "", coordY: ""});
}
}
},
methods: {
}
}
</script>
Whats going on:
Set up a v-model on the input which takes the number of nodes and bind it to nodes property.
initialized a new property nodesArr : [] which will be used to loop through to display each Coord input
set up a watcher on nodes which loops through the number of nodes entered and pushes those many objects {coordX: "", coordY: ""} to nodesArr array
we loop through nodesArr using v-for="(node, index) in nodesArr" to display the inputs for x-coord and y-coord
The x-coord input is bound to the corresponding coordX property making use of the index we get in v-for
Similarly the y-coord input is bound to the corresponding coordY property making use of the index we get in v-for
since the inputs are two way bound using v-model you have all the input data in nodesArr property which can be used as you wish

Categories

Resources