I saw some documentation on v-select and slots, but didn't really understand if I can apply it for my example codepen.
I just need to get the selected text (not the value), and use it somewhere in the code:
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
state: {},
selectedText: "",
states: [
{ value: "a", text: "alpha" },
{ value: "b", text: "beta" },
{ value: "g", text: "gamma" }
]
},
methods: {
change: (newValue) => {
// do something with the text
// "alpha", "beta", or "gama"
console.log(newValue);
}
}
});
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container fluid>
<label>my selected text is: {{state}}</label>
<v-row align="center">
<v-col cols="3">
<v-select v-model="state" :items="states" #change="change" :text="selectedText"></v-select>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
You need to add return-object prop to <v-select>
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
state: null,
selectedText: "",
states: [
{ value: "a", text: "alpha" },
{ value: "b", text: "beta" },
{ value: "g", text: "gamma" }
]
},
methods: {
change: (newValue) => {
// do something with the text
// "alpha", "beta", or "gama"
console.log(newValue.text);
}
}
});
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container fluid>
<label>my selected text is: {{state && state.text}}</label>
<v-row align="center">
<v-col cols="3">
<v-select :items="states" v-model="state" #change="change" item-text="text" return-object></v-select>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
Edit:
Ok so based on your approach, the solution would be to use the country code to find appropriate country object in the country list and set that.
Here is how you would solve it:
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
country: "c",
countries: [{
code: "a",
name: "Ameriga Fatela"
},
{
code: "b",
name: "Bolivia Grande"
},
{
code: "c",
name: "Comore Potentia"
}
]
},
methods: {
getCountryCode() {
return "b"; // have no c.name here!
},
change() {
var newCode = this.getCountryCode();
// Since we were getting objects when changing options, we must also set objects
this.country = this.countries.filter(country => country.code === newCode)[0];
}
}
});
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<v-container>
<div>current code is >{{country.code}}<</div>
<div>current name is >{{country.name}}<</div>
<v-row>
<v-col cols="12">
<v-select v-model="country" :items="countries" item-text="name" item-value="code" return-object></v-select>
<v-btn #click="change">change by script to 'b'</v-btn>
</vcol>
</v-row>
</v-container>
</v-app>
</div>
Your states objects contain both value and text properties. If you change value to key v-select recognizes the change and you can access the text property via this.state. Like so:
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
state: {},
selectedText: "",
states: [
{ key: "a", text: "alpha" },
{ key: "b", text: "beta" },
{ key: "g", text: "gamma" }
]
},
methods: {
change: (newValue) => {
// do something with the text
// "alpha", "beta", or "gama"
console.log(newValue); // Also returns text attribute instead of key
}
}
});
<div id="app">
<v-app id="inspire">
<v-container fluid>
<label>my selected text is: {{state}}</label>
<v-row align="center">
<v-col cols="3">
<v-select v-model="state" :items="states" #change="change"></v-select>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
EDIT:
The best option I found is to use a computed property for the selected text, without changes to the current code (go in FullPage after lauching the snippet to correctly see the output):
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
countries: [
{ code: "a", name: "Ameriga Fatela" },
{ code: "b", name: "Bolivia Grande" },
{ code: "c", name: "Comore Potentia" }
],
country: "b"
},
methods: {
getCountryCode() {
return "c"; // have no c.name here!
},
change() {
this.country = this.getCountryCode();
}
},
computed: {
countryName() {
return this.countries.find((c) => c.code === this.country).name;
}
}
});
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<v-container>
<div>current code is >{{country}}<</div>
<div>current name is >{{countryName}}<</div>
<v-row>
<v-col cols="12">
<v-select v-model="country" :items="countries" item-text="name" item-value="code"></v-select>
<v-btn #click="change">change by script to '{{getCountryCode()}}'</v-btn>
</vcol>
</v-row>
</v-container>
</v-app>
</div>
Another option is (Codepen here) the suggestion of Anurag Srivastava to use return-object, I returned the object. However, it have some drawbacks, cause actually I am not able to properly change the value by code:
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
country: "c",
countries: [
{ code: "a", name: "Ameriga Fatela" },
{ code: "b", name: "Bolivia Grande" },
{ code: "c", name: "Comore Potentia" }
]
},
methods: {
getCountryCode() {
return "b"; // have no c.name here!
},
change() {
var newCode = this.getCountryCode();
this.country = newCode;
}
}
});
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.20/dist/vuetify.min.js"></script>
<div id="app">
<v-app>
<v-container>
<div>current code is >{{country.code}}<</div>
<div>current name is >{{country.name}}<</div>
<v-row>
<v-col cols="12">
<v-select v-model="country" :items="countries" item-text="name" item-value="code" return-object></v-select>
<v-btn #click="change">change by script to 'b'</v-btn>
</vcol>
</v-row>
</v-container>
</v-app>
</div>
However, in both cases we should recalculate the country name. That is not good. Imagine to build the combobox we have to do a heavy operation... recalculating it each time is time-consuming and really not optimal....
Related
In the code below I am using a v-autocomplete component
and a variable select where the selected value is stored.
The watch logs the value and type of select.
The problem I'm facing is that when the text typed in the v-autocomplete is cleared, select defaults to null instead of an empty string.
Is there any way to revert select to an empty string instead of a null object?
<div id="app">
<v-app id="inspire">
<v-card>
<v-container fluid>
<v-row
align="center"
>
<v-col cols="12">
<v-autocomplete
v-model="select"
:items="items"
dense
filled
label="Filled"
clearable
></v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-card>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: ['foo', 'bar', 'fizz', 'buzz'],
select: "",
}),
watch:{
value:function(value){
console.log(this.select) // select value
console.log(typeof(this.value)); // select variable type
}
}
})
v-model='select' is a shorthand for :value="select" and #input="select = $event". Thus, if you want to customize the behaviour of emitted #input event, you can write it in expanded form.
In below snippet, when the input value changes, you assign it to select if it is not null, or assign an empty string otherwise.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: ['foo', 'bar', 'fizz', 'buzz'],
select: "",
}),
watch:{
select:function(value){
console.log(value) // select value
console.log(typeof(value)); // select variable type
}
}
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<v-app id="inspire">
<v-card>
<v-container fluid>
<v-row
align="center"
>
<v-col cols="12">
<v-autocomplete
:value="select"
#input="select = $event || ''"
:items="items"
dense
filled
label="Filled"
clearable
></v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-card>
</v-app>
</div>
So I am trying to check the checkbox Icon to something more custom, perhaps a different icon, however, I tried a couple different things like pseudo elements with no success. right now what this does is loops through data and displays the name and when checked highlights it based on the css class. What I am trying to do is when check change the checkbox icon.
css
.unchecked{
color: gray;
}
.checked{
background-color: #ffff00;
}
Vuejs Component.
Vue.component('check-list', {
template: `
<v-container>
<v-row >
<v-col >
<v-checkbox
v-for="item in values"
:key="item.id"
:value="item.id"
v-model="selected"
>
<template v-slot:label>
<div :class="selected.includes(item.id) ? 'checked' : 'unchecked'">
{{item.name}}
</div>
</template>
</v-checkbox>
</v-col>
</v-row>
<pre>{{selected}}</pre>
</v-container>
`,
data: function () {
return {
selected: [],
values: [
{id:'1',name:'Name 1'},
{id:'2', name:'Name 2'},
{id:'3', name:'Name 3'},
],
ex4: ['red']
}
},
methods: {
},
})
new Vue({
el: '#components-demo',
vuetify: new Vuetify({
icons: {
iconfont: 'md',
},
}),
data: () => ({
}),
})
#chewie, it is possible to change the checkbox icon in Vuetify, There is a specia prop to handle this
:on-icon="'icon-name'"
:off-icon="'icon-name'"
Please find the full code below
<div id="app">
<v-app id="inspire">
<v-container
class="px-0"
fluid
>
<v-row >
<v-col >
<v-checkbox
:on-icon="'mdi-heart'"
:off-icon="'mdi-home'"
v-for="item in values"
:key="item.id"
:value="item.id"
v-model="selected"
>
<template v-slot:label>
<div :class="selected.includes(item.id) ? 'checked' : 'unchecked'">
{{item.name}}
</div>
</template>
</v-checkbox>
</v-col>
</v-row>
<pre>{{selected}}</pre>
</v-container>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
selected: [],
values: [
{id:'1',name:'Name 1'},
{id:'2', name:'Name 2'},
{id:'3', name:'Name 3'},
],
ex4: ['red']
}
},
})
Please find the working codepen here:
https://codepen.io/chansv/pen/QWdEPvB?editors=1010
I am trying to create an app where users can select what kind of vuetify element they would like to render on the page? So I have 4 options that users can select from. I want to render the respective vuetify component on click, so if the user selects divider a <v-divider> </v-divider> should render, for a spacer, a <v-spacer></v-spacer> and for a toolbar a <v-toolbar></v-toolbar> and if they select text then a <v-btn></v-btn> with text would be displayed. I am really stuck on how I can do it.
This is a sample codepen
new Vue({
el: "#app",
data() {
return {
elements: [{
title: "Divider",
value: "divider"
},
{
title: "Spacer",
value: "spacer"
},
{
title: "Toolbar",
value: "toolbar"
},
{
title: "Text",
value: "text"
}
],
selected: []
};
},
methods: {
renderElements() {
console.log(this.selected);
this.selected = [];
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout column>
<v-flex v-for="el in elements" :key="el.value">
<v-checkbox :value="el.value" v-model="selected" :label="el.title"></v-checkbox>
</v-flex>
<v-btn #click="renderElements"> Render Dynamic Elements</v-btn>
</v-layout>
</v-container>
</v-app>
</div>
I would really appreciate some help with this.
It seems you need to use dynamic components:
<component v-for="(el, i) in selected" :key="i" :is="el.value"></component>
new Vue({
el: "#app",
data() {
return {
elements: [
{
title: "Divider",
value: "v-divider"
},
{
title: "Spacer",
value: "v-spacer"
},
{
title: "Toolbar",
value: "v-toolbar"
},
{
title: "Text",
value: "v-btn"
}
],
selected: []
};
},
methods: {
renderElements() {
console.log(this.selected);
this.selected = [];
}
}
});
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout column>
<v-flex v-for="el in elements" :key="el.value">
<v-checkbox :value="el" v-model="selected" :label="el.title">
</v-checkbox>
</v-flex>
<v-btn #click="renderElements"> Render Dynamic Elements</v-btn>
<component v-for="(el, i) in selected" :key="i" :is="el.value"></component>
</v-layout>
</v-container>
</v-app>
</div>
new Vue({
el: "#app",
data() {
return {
elements: [
{
title: "Divider",
value: "v-divider",
show: false
},
{
title: "Spacer",
value: "v-spacer",
show: false
},
{
title: "Toolbar",
value: "v-toolbar",
show: false
},
{
title: "Text",
value: "v-btn",
show: false
}
],
selected: []
};
},
methods: {
renderElements() {
console.log(this.selected);
for(let i=0; i<this.elements.length; i++)
{
this.elements[i].show = this.selected.includes(i);
}
}
}
});
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout column>
<v-checkbox v-for="(item, i) in elements"
:key="i"
:label="item.title"
:value="i"
v-model="selected"
></v-checkbox>
<v-btn #click="renderElements"> Render Dynamic Elements</v-btn>
<component v-for="(item, i) in elements" :key="i + 10" :is="item.value" v-if="item.show">{{ item.title }}</component>
</v-layout>
</v-container>
</v-app>
</div>
I am trying to loop in VueJS using v-for but for some reason the text doesn't seem to be rendering. Not sure what i am doing wrong?
This is my sample pen
new Vue({
el: "#app",
data() {
return {
inputValue: "",
myArray: []
};
},
methods: {
createArray() {
this.myArray.push(this.inputValue);
console.log(this.myArray);
},
clear() {
this.inputValue = "";
this.myArray = [];
console.log(this.myArray);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app id="inspire">
<v-layout justify-center>
<v-flex xs6>
<v-text-field v-model="inputValue">
</v-text-field>
<v-btn :disabled="inputValue === ''" #click="createArray">Click Me</v-btn>
<v-btn #click="clear">Clear</v-btn>
<div v-if="myArray.length > 0">
<div v-for="(item,i) in myArray"></div>
<li>{{item}}</li>
</div>
</v-flex>
</v-layout>
</v-app>
</div>
Any help will be appreciated. Thank you,
You put a </div> at the wrong place.
Here it should be :
<div v-for="(item,i) in myArray">
<li>{{item}}</li>
</div>
I am trying to open my CanvasPreview Component in another component but it fails,
first, it quickly shows the dialog/modal afterward it gets hidden again if I open the Vue Dev tool
the showCanvasPreview is set to false if I manually edit it in my console to true the modal gets shown.
So I guess that it gets set to false again, but I can't see why.
This is the dialog/modal component:
<template>
<v-dialog
v-model="show"
>
<v-card>
<v-card-actions>
<v-container grid-list-md text-xs-center>
<v-layout row wrap>
</v-layout>
</v-container>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import CanvasPreviewSourceUpload from './CanvasPreviewSourceUpload';
export default {
components: {
'canvas-preview-source-upload': CanvasPreviewSourceUpload
},
props: {
imgSrc: String,
visible: Boolean
},
computed: {
show: {
get () {
return this.visible;
},
set (visible) {
if (!visible) {
this.$emit('closePreview');
}
}
}
},
}
</script>
And in my parent component I call the preview component like this:
<template>
<div>
//... some more html
<div id="canvas-body">
<canvas id="pdf-render"></canvas>
<canvas id="selectCanvas"
#mousedown="markElementOnMouseDown"
#mousemove="updatePreview"
#mouseup="markElementOnMouseUp">
</canvas>
</div>
<canvas-preview
:imgSrc="this.targetImage.src"
:visible="showCanvasPreview"
#closePreview="showCanvasPreview=false">
</canvas-preview>
</div>
</template>
<script>
import CanvasPreview from '#/js/components/CanvasPreview';
export default {
components: {
'canvas-preview': CanvasPreview
},
props: {
'name': String
},
data: () => ({
showCanvasPreview: false,
...
}),
methods: {
markElementOnMouseUp (event) {
this.isDragging = false;
this.targetImage.src = this.clipCanvas.toDataURL();
this.targetImage.style.display = 'block';
this.showCanvasPreview = true;
console.log("mouseup: " + this.showCanvasPreview);
},
}
</script>
Try this one
<v-dialog
v-model="show"
>
<v-card>
<v-card-actions>
<v-container grid-list-md text-xs-center>
<v-layout row wrap>
<canvas-preview-source-upload
:imgSrc="imgSrc"
#close.stop="show=false">
</canvas-preview-source-upload>
</v-layout>
</v-container>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import CanvasPreviewSourceUpload from './CanvasPreviewSourceUpload';
export default {
components: {
'canvas-preview-source-upload': CanvasPreviewSourceUpload
},
data: ()=> ({
show: false
}),
props: {
imgSrc: String,
visible: Boolean
},
watch: {
show(isShow){
if (!isShow) {
this.$emit('closePreview');
}
}
visible(isVisible) {
this.show = isVisible;
}
}
}
</script>```
Something like this should allow you to open a v-dialog from a separate component..
If you supply a CodePen or CodeSandbox with your code in it, we would be able to better assist you.
[CodePen mirror]
const dialog = {
template: "#dialog",
props: {
value: {
type: Boolean,
required: true
},
},
computed: {
show: {
get() {
return this.value;
},
set(value) {
this.$emit("input", value);
}
}
},
};
const dialogWrapper = {
template: "#dialogWrapper",
components: {
appDialog: dialog,
},
data() {
return {
isShown: false,
}
}
}
new Vue({
el: "#app",
components: {
dialogWrapper
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.6/dist/vuetify.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.6/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app>
<v-content>
<dialog-wrapper/>
</v-content>
</v-app>
</div>
<script type="text/x-template" id="dialog">
<v-dialog v-model="show">
<v-card>
<v-card-actions pa-0>
<v-spacer/>
<v-btn dark small color="red" #click="show = false">Close</v-btn>
<v-spacer/>
</v-card-actions>
<v-card-title class="justify-center">
<h2>
Hello from the child dialog
</h2>
</v-card-title>
</v-card>
</v-dialog>
</script>
<script type="text/x-template" id="dialogWrapper">
<div>
<h1 class="text-xs-center">I am the wrapper/parent</h1>
<v-container>
<v-layout justify-center>
<v-btn color="primary" dark #click.stop="isShown = true">
Open Dialog
</v-btn>
</v-layout>
</v-container>
<app-dialog v-model="isShown"></app-dialog>
</div>
</script>