Get all input values from dynamic form in Vuejs - vue.js

I have some reusable components:
TextField
Form
And a component where I import them both. I pass the TextField component as props to the Form. In this Form component I have a submit button which needs to get all the values from the passed TextField components. As far as I could read in the docs I could use the v-model to get the values. But for some reason I can't find how to get those values in my Form component. Maybe I am missing something and I hope someone can help me with it. I already took a look at this question: Get all Input values - Vuejs. However, this didn't solve my problem.
The TextField component looks like this:
<template>
<v-text-field
v-model="vModel"
:rules="rules"
:counter="counter"
:label="label"
:required="required"
:placeholder="placeholder"
:value="value"
></v-text-field>
</template>
<script>
export default {
name: "TextField",
props: {
rules: Array,
counter: Number,
label: String,
required: {
type: Boolean,
default: true
},
placeholder: String,
value: String
},
data: () => ({
vModel: '',
}),
};
</script>
The Form component looks like this:
<template>
<v-form>
<v-container>
<slot></slot>
<v-btn class="mr-4" #click="submit">Submit</v-btn>
</v-container>
</v-form>
</template>
<script>
export default {
methods: {
submit () {
// console.log form data
}
}
};
</script>
And the component where I import both components:
<template>
<Form>
<v-row>
<v-col cols="12" md="4">
<TextField :label="'Email address'" :vModel="email"/>
</v-col>
</v-row>
</Form>
</template>
<script>
import Form from "../../../components/Form/Form";
import TextField from "../../../components/Form/TextField";
export default {
components: {
Form,
TextField,
},
data: () => ({
email: '',
})
};
</script>
I also created a CodeSandBox.
Can anyone give me some advice on how I might get the v-model values from the TextField components inside the Form component? If it's not possible, or I might do this better in another way please let me know.

v-model is simply a shorthand to create two things:
a :value binding (passed as a prop to your component)
a #input event handler
Currently, the vModel variable in your TextField component may receive the value, but it does not send it back to the parent component.
You could try something like this:
TextField
<template>
<v-text-field
v-model="localValue"
:rules="rules"
:counter="counter"
:label="label"
:required="required"
:placeholder="placeholder"
></v-text-field>
</template>
<script>
export default {
name: "TextField",
props: {
rules: Array,
counter: Number,
label: String,
required: {
type: Boolean,
default: true
},
placeholder: String,
value: String
},
data: () => ({
localValue: '',
}),
created() {
this.localValue = this.value;
this.$watch('localValue', (value) => {
this.$emit('input', value);
}
}
};
</script>
Form
<template>
<v-form>
<v-container>
<slot></slot>
<v-btn class="mr-4" #click="submit">Submit</v-btn>
</v-container>
</v-form>
</template>
<script>
export default {
props: ['form'],
methods: {
submit () {
alert(JSON.stringify(this.form));
}
}
};
</script>
Your final component:
<template>
<Form :form="form">
<v-row>
<v-col cols="12" md="4">
<TextField :label="'Email address'" v-model="formvalentin#whatdafox.com"/>
</v-col>
</v-row>
</Form>
</template>
<script>
import Form from "../../../components/Form/Form";
import TextField from "../../../components/Form/TextField";
export default {
components: {
Form,
TextField,
},
data: () => ({
form: {
email: ''
}
})
};
</script>
More information on v-model: https://v2.vuejs.org/v2/guide/forms.html

Not exactly sure as to what you doing in your code, but to simplify the template and component with v-model would look something like the code below.
ContactUs.vue
<template>
<form method="POST"
autocomplete="off"
class="form--container relative box-col-center w-full"
name="contact"
action="/form/contact"
#submit.prevent="onSubmit">
<input class="form--field font-poppins w-full"
type="text"
name="name"
v-model="field.name"
placeholder="Your name"
autocomplete='name'>
<input class="form--field font-poppins w-full"
type="email"
id="email"
name="email"
v-model="field.email"
placeholder="Your email"
autocomplete='email'>
<textarea class="textarea form--field font-poppins w-full"
id="body"
name="body"
placeholder="I'd like to know about ..."
v-model="field.body"
rows="5">
</textarea>
<button type="submit"
#click.prevent="onSubmit()"
class="container--row container--center btn--purple btn--040 w-2/3 lg:w-full">
<span class="text--w-full uppercase">Submit</span>
</button>
</form>
</template>
<script>
export default {
name: 'ContactUs',
data() {
return {
fields:{
name: '',
email: '',
body: ''
},
}
},
methods: {
onSubmit() {
let vm = this;
return new Promise((resolve, reject) => {
axios.post('/forms/contact', vm.fields)
.then(response => {
resolve(response.data);
}).catch(err => {
reject(err.response);
});
});
},
}
}
</script>
If you are attempting to create a Form service class then it would almost the same, except you would abstract the form logic to that class.
FormService.js
export default class Form {
/**
* Create a new Form instance.
*
* #param {object} data
* #param type
*/
constructor(data) {
this.originalData = data;
for (let field in data) {
this[field] = data[field];
}
}
/**
* Submit the form.
*
* #param {string} requestType
* #param {string} url
*/
submit(requestType, url) {
return new Promise((resolve, reject) => {
axios[requestType](url, this.data())
.then(response => {
resolve(response.data);
}).catch(err => {
reject(err.response);
});
});
}
}
and then in your component, you would inject the form services and use the data
ContactUs.vue
import Form from '../services/FormService.js';
export default {
name: 'ContactUs',
data() {
return {
fields: new Form({
name: '',
email: '',
body: ''
}),
}
},
methods: {
onSubmit() {
let self = this;
self.form.post('/forms/contact')
.then(response => {
}).catch((err) => {
})
},
}

Related

Vue component prop not updating on $emit

I need to update the component's prop on every route change but it stays with the last info given.
For example, I fill the form in RouteTwo, with id, name, lastname and phone, and if I change to RouteOne, ComponentOne stays with those four values (including phone) until I start filling the form in RouteOne.
I'm working with vue 2.6.12, vue-router 3.4.9
Here's an example code:
General.vue
<template>
<div>
<div>
<router-view #data-updated="updateFunction"></router-view>
</div>
<div>
<component-one v-bind:component-prop="reactiveProp" />
</div>
</div>
</template>
<script>
import ComponentOne from './ComponentOne.vue';
export default {
components: {
ComponentOne,
},
data: () => ({
reactiveProp
}),
methods: {
updateFunction(value) {
this.reactiveProp = value;
},
}
}
</script>
ComponentOne.vue
<template>
<div>
<p>{{ componentProp.id }}</p>
<p>{{ componentProp.name }}</p>
<p>{{ componentProp.lastname }}</p>
<p v-if="routePath == 'routetwo'">{{ componentProp.phone }}</p>
</div>
</template>
<script>
export default {
props: {
componentProp: Object,
},
data: () => ({
routePath: ''
}),
mounted() {
this.routePath = this.$route.path.split('/').at(-1);
},
}
</script>
RouteOne.vue
<template>
<div>
<input type="text" v-model="dataObject.id" />
<input type="text" v-model="dataObject.name" />
<input type="text" v-model="dataObject.lastname" />
</div>
</template>
<script>
export default {
data: () => ({
dataObject: {
id: '',
name: '',
lastname: '',
},
}),
methods: {
// some logic methods
},
watch: {
dataObject: {
handler: function() {
this.$emit('data-updated',this.dataObject);
},
deep: true,
}
},
}
</scipt>
RouteTwo.vue
<template>
<div>
<input type="text" v-model="dataObject.id" />
<input type="text" v-model="dataObject.name" />
<input type="text" v-model="dataObject.lastname" />
<input type="text" v-model="dataObject.phone" />
</div>
</template>
<script>
export default {
data: () => ({
dataObject: {
id: '',
name: '',
lastname: '',
phone: '',
},
}),
methods: {
// some logic methods
},
watch: {
dataObject: {
handler: function() {
this.$emit('data-updated',this.dataObject);
},
deep: true,
}
},
}
</scipt>
Router
{
name: 'general',
path: '/general',
component: () => import('General.vue'),
children: [
{
name: 'route-one',
path: 'routeone',
component: () => import('RouteOne.vue')
},
{
name: 'route-two',
path: 'routetwo',
component: () => import('RouteTwo.vue')
}
]
}
Switching routes doesn't cause a change in dataObject, so no emit will fire. Technically, switching routes causes one route component to be unmounted (destroyed), and the next route component to be created, meaning dataObject is created/recreated every time you switch back and forth, which is fundamentally different from dataObject being "changed" (which activates the watcher).
Instead, put a watcher on the route itself in the General component and reset reactiveProp when that watcher activates. This will clear the fields when going between RouteOne and RouteTwo:
watch: {
$route(to, from) {
this.reactiveProp = {};
},
},

vuejs2 slots how to communicate with parent

I want to create a formRow component that have a slot for the input field and vee-validate for validation
this is my markup
//form
<vFormRow validate="required" v-slot="{ onInput, errors }">
<vTextfield #input="onInput" :errors="errors"/>
</vFormRow>
I tried to emit the value to the parent and get the value with #input="onInput" on the slot, but this doesn't work
//formrow
<template>
<div class="mb-4">
<v-validation-provider
v-slot="{ errors }"
:rules="validate"
>
<label>{{ label }}</label>
<slot
:onInput="onInput"
:errors="errors"
/>
<vFormError
:message="errors[0]"
/>
</v-validation-provider>
</div>
</template>
<script>
import { ValidationProvider as vValidationProvider } from 'vee-validate'
import vRadioButton from '#primitives/textfield'
import vFormError from '#primitives/formError'
export default {
components: {
vTextfield,
vFormError,
vValidationProvider
},
props: {
value: {
type: String,
default: '',
},
validate: {
type: String,
required: true,
}
},
methods: {
onInput(value) {
console.log(value)
}
}
}
</script>
//textfield
<template>
<div>
<input :value="value" #input="onInput"/>
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: '',
},
errors: {
type: Array,
default: () => {}
}
},
data: {
return {
// local_value: ''
}
}
methods: {
onInput(e) {
// this.local_value = e.target.value
this.$emit('input', e.target.value)
}
}
}
</script>
What I'm doing wrong?
You're not actually passing the slot props to <vTextfield>. I think you might be assuming that data bindings and event handlers on the <slot> are automatically applied to the slot's children, but that's not true.
To use the value slot prop, destructure it from v-slot, and bind it to the <vTextfield> child:
<vFormRow validate="required" v-slot="{ value }">
<vTextfield :value="value" />
</vFormRow>
You could also pass the onInput method as a slot prop:
// vFormRow.vue
<slot :onInput="onInput" />
Then bind the event handler to <vTextfield>:
<vFormRow validate="required" v-slot="{ onInput }">
<vTextfield #input="onInput" />
</vFormRow>

Vue composition API is not reactive inside v-for?

I am using Vue 2 and Vuetify (not Vue 3) to create a form builder website. I was going perfectly well until I found out that something is wrong. So here's the case. I rendered text fields (inputs) from a reactive array using the following code.
<template>
// ... some other unrelated code
<template v-if="answer.type !== 1">
<v-col
v-for="(_, i) in answer.options"
:key="`#question-${answer.id}-${i}`"
cols="12"
>
<div class="flex flex-row justify-between items-center">
<TextField
v-model="answer.options[i]"
class="ml-4"
label="Option"
underlined
hideLabel
/>
<v-btn #click="deleteOption(i)" icon>
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
</v-col>
<v-col>
<TextButton #click="addOption()" text="+ ADD OPTION" />
</v-col>
</template>
// ... some other unrelated code
</template>
<script>
import { reactive, ref, watch } from '#vue/composition-api'
import useInquiry from '#/composables/useInquiry'
import TextButton from '#/components/clickables/TextButton.vue'
import TextField from '#/components/inputs/TextField.vue'
export default {
components: { TextField, TextButton },
setup() {
const { answer, addOption, deleteOption } = useInquiry()
return { answer, addOption, deleteOption }
}
}
</script>
Here's my useInquiry composable logic
import { reactive, watch, se } from '#vue/composition-api'
import ID from '#/helpers/id'
export default () => {
const answer = reactive({
id: ID(), // this literally just generates an ID
type: 2,
options: ['', '']
})
const addOption = () => {
answer.options.push('')
}
const deleteOption = at => {
const temp = answer.options.filter((_, i) => i !== at)
answer.options = []
answer.options = temp
};
return { answer, addOption, deleteOption }
}
And finally, here's my TextField.vue
<template>
<v-text-field
v-model="inputValue"
:label="label"
:single-line="hideLabel"
:type="password ? 'password' : 'text'"
:outlined="!underlined"
:dense="!large"
hide-details="auto"
/>
</template>
<script>
import { ref, watch } from '#vue/composition-api'
export default {
model: {
props: 'value',
event: 'change'
},
props: {
label: String,
value: String,
password: Boolean,
underlined: Boolean,
large: Boolean,
hideLabel: Boolean
},
setup(props, context) {
const inputValue = ref(props.value)
watch(inputValue, (currInput, prevInput) => {
context.emit('change', currInput)
})
return { inputValue }
}
}
</script>
The problem is, everytime the delete button is clicked, the deleted input is always the last one on the array, even though I didn't click on last one. I tried to log my reactive array by watching it using Vue's composition watch method. Apparently, the data is correctly updated. The problem is the v-model looks un-synced and the last input is always the one that gets deleted.
Looks good to me ....except the TextField.vue
Problem is in TextField.vue. What you actually doing inside setup of TextField.vue is this (Vue 2 API):
data() {
return {
inputValue: this.value
}
}
...this is one time initialization of inputValue data member with value of value prop. So when one of the options is removed and components are reused (because that's what Vue does all the time - especially when index is used in :key) inputValue is not updated to a new value of value prop...
You don't need inputValue or model option at all, just remove it and use this template:
<v-text-field
:value="value"
#input="$emit('input', $event)"
:label="label"
:single-line="hideLabel"
:type="password ? 'password' : 'text'"
:outlined="!underlined"
:dense="!large"
hide-details="auto"
/>
NOTE that in my example I'm using $event.target.value instead of just $event because I'm working with native <input> element and not Vuetify's custom component input...
working example...
const {
reactive,
ref,
watch
} = VueCompositionAPI
Vue.use(VueCompositionAPI)
const BrokenInput = {
model: {
props: 'value',
event: 'change'
},
props: {
value: String,
},
setup(props, context) {
const inputValue = ref(props.value)
watch(inputValue, (currInput, prevInput) => {
context.emit('change', currInput)
})
return {
inputValue
}
},
template: `<input type="text" v-model="inputValue" />`
}
const FixedInput = {
props: {
value: String,
},
template: `<input type="text" :value="value" #input="$emit('input', $event.target.value)"/>`
}
const useInquiry = () => {
const answer = reactive({
id: 1,
type: 2,
options: ['1', '2', '3', '4', '5']
})
const addOption = () => {
answer.options.push('')
}
const deleteOption = at => {
const temp = answer.options.filter((_, i) => i !== at)
answer.options = temp
};
return {
answer,
addOption,
deleteOption
}
}
const app = new Vue({
components: { 'broken-input': BrokenInput, 'fixed-input': FixedInput },
setup() {
return useInquiry()
},
})
app.$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#vue/composition-api#1.0.0-beta.18"></script>
<div id="app">
<table>
<tr>
<th>Option</th>
<th>Broken input</th>
<th>Model</th>
<th>Fixed input</th>
<th></th>
<tr>
<tr v-for="(_, i) in answer.options" :key="'#question-'+ answer.id + '-' + i">
<td>Option {{ i }}:</td>
<td>
<broken-input v-model="answer.options[i]" />
</td>
<td>
{{ answer.options[i] }}
</td>
<td>
<fixed-input v-model="answer.options[i]" />
</td>
<td><button #click="deleteOption(i)">Remove option</button></td>
</tr>
</table>
<button #click="addOption()">Add option</button>
</div>

Vue.js - Inject el elements to html

I have website for online tests.
One of the question that i have created on the test its topic "Fill in the blank", which means fill in the blank spaces words.
The question comes from the server as a string like that "Today is a [1] day, and i should [2] today".
What i want to do is to get that string and replace all the [] with el-input.
I have done something like that
<template>
<div class="d-flex flex-column mg-t-20 pd-10">
<h6 class="tx-gray-800">Fill in the blank areas the missing words</h6>
<div class="mg-t-20" v-html="generateFillBlankQuestion(question.question)" />
</div>
</template>
<script>
export default {
name: 'FillBlank',
directives: {},
props: [ 'question' ],
components: {
},
computed: {},
data() {
return {
input: ''
}
},
filters: {},
created() {
},
methods: {
generateFillBlankQuestion(question) {
var matches = question.match((/\[\d\]/g))
console.log(matches)
matches.forEach((element) => {
console.log(element)
question = question.replace(element, '<el-input />')
})
console.log(question)
return question
}
}
}
On this line question = question.replace(element, '<el-input />') I'm replacing the [] to input.
For some reason when i try to replace it to <el-input> it doesn't render it.
But if i use <input type='text'> it renders it.
Is it possible to inject el elements?
If you are not using the Vue run-time template compiler you can not render Vue components inside v-html. You should do something like this:
<template>
<div class="d-flex flex-column mg-t-20 pd-10">
<h6 class="tx-gray-800">Fill in the blank areas the missing words</h6>
<div class="mg-t-20">
<template v-for="(word,idx) in wordList">
<el-input v-if="word.blank" v-model="word.value" :key="idx" />
<template v-else>{{ word.text }}</template>
</template>
</div>
</div>
</template>
<script>
export default
{
name: 'FillBlank',
props:
{
question:
{
type: String,
default: ''
}
},
computed:
{
wordList()
{
const words = this.question.split(' ');
return words.map(word =>
({
value: '',
text: word,
blank: /^\[\d+\]$/.test(word),
}));
}
}
}

want to use vuetify snackbar as a global custom component in vuejs

i used snackbar to show success messages in vuejs. i want to make a global custom snackbar component.
<template>
<div name="snackbars">
<v-snackbar
v-model="snackbar"
:color="color"
:timeout="timeout"
:top="'top'"
>
{{ text }}
<template v-slot:action="{ attrs }">
<v-btn dark text v-bind="attrs" #click="snackbar = false">
Close
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
props: {
snackbar: {
type: Boolean,
required: true,
},
color: {
type: String,
required: false,
default: "success",
},
timeout: {
type: Number,
required: false,
default: 3000,
},
text: {
type: String,
required: true,
},
},
};
</script>
then i import this as a component in my every form like this.
<SnackBar :snackbar="snackbar" :color="color" :text="text" />
but my issue is i can't use snackbar as a prop in my child component. it shows me this error.
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "snackbar"
how can i fix this issue. can anyone help me?
I realize this is old, but thanks to google, I am going to add my solution.
I use this, because I don't see the point of using vuex for a snackbar. It's more work then needed.
Create a vue component named vtoast
<template>
<v-snackbar
:color="color"
:timeout="timer"
v-model="showSnackbar"
bottom
right
>
<v-icon left>{{icon}}</v-icon>{{message}}
</v-snackbar>
</template>
<script>
export default {
name: "vtoast",
data() {
return{
showSnackbar: false,
message: '',
color: 'success',
icon: 'mdi-check',
timer: 3000
}
},
methods:{
show(data) {
this.message = data.message || 'missing "message".'
this.color = data.color || 'success'
this.timer = data.timer || 3000
this.icon = data.icon || 'mdi-check'
this.showSnackbar = true
}
}
}
</script>
Somewhere in the root of your main app, add the following. (I usually put mine in App.vue)
<template>
...
<!-- toast -->
<vtoast ref="vtoast"/>
...
</template>
<script>
import vtoast from '#/your/vtoast/directory/vtoast'
export default{
name: 'App', //or whatever your root is
components:{
vtoast
},
mounted() {
this.$root.vtoast = this.$refs.vtoast
},
}
</script>
And access it like so...
this.$root.vtoast.show()
this.$root.vtoast.show({message: 'Ahoy there!'})
i found a way to fix my solution using vuex.
<template>
<div name="snackbars">
<v-snackbar v-model="show" :color="color" :timeout="timeout" :top="'top'">
{{ text }}
<template v-slot:action="{ attrs }">
<v-btn dark text v-bind="attrs" #click="show = false">
Close
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
created() {
this.$store.subscribe((mutation, state) => {
if (mutation.type === "snackbar/SHOW_MESSAGE") {
this.text = state.snackbar.text;
this.color = state.snackbar.color;
this.timeout = state.snackbar.timeout;
this.show = true;
}
});
},
data() {
return {
show: false,
color: "",
text: "",
timeout: 0,
};
},
};
</script>
in my vuex module i wrote like this
export default {
namespaced: true,
state: {
text: "",
color: "",
timeout: "",
},
mutations: {
SHOW_MESSAGE(state, payload) {
state.text = payload.text;
state.color = payload.color;
state.timeout = payload.timeout;
},
},
actions: {
showSnack({ commit }, payload) {
commit("SHOW_MESSAGE", payload);
},
},
};
then i import snackbar child component into my parent component and send data like this.
...mapActions("snackbar", ["showSnack"]),
saveDetails() {
this.showSnack({
text: "Successfully Saved!",
color: "success",
timeout: 3500,
});
}
Another solution is to use a computed value with getter and setter.
Using options api
<template>
<v-snackbar v-model="show" :color="color">
{{ message }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" #click="show = false">Close</v-btn>
</template>
</v-snackbar>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
message: 'snackbar/message',
color: 'snackbar/color'
}),
show: {
get() {
return this.$store.state.snackbar.show
},
set(v) {
this.$store.commit('snackbar/SET_SHOW', v)
}
}
}
}
</script>
Using composition api plugin
<template>
<v-snackbar v-model="show" :color="color">
{{ message }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" #click="show = false">Close</v-btn>
</template>
</v-snackbar>
</template>
<script>
import { defineComponent, computed } from '#vue/composition-api';
export default defineComponent({
setup(_props, { root }) {
const show = computed({
get: () => root.$store.state.snackbar.show,
set: (v) => root.$store.commit('snackbar/SET_SHOW', v),
});
const message = computed(() => root.$store.state.snackbar.message);
const color = computed(() => root.$store.state.snackbar.color);
return {
show,
message,
color,
};
},
});
</script>
A better implementation using composables here https://gist.github.com/wobsoriano/2f3f0480f24298e150be0c13f93bac20
You are having a prop and the same in data.
remove snackbar from data() as it is available from prop.
<script>
export default {
props: {
snackbar: {
type: Boolean,
required: true,
},
color: {
type: String,
required: false,
default: "success",
},
timeout: {
type: Number,
required: false,
default: 3000,
},
text: {
type: String,
required: true,
},
}
};
</script>
This is what I did with Options API with mere props and events;
Here is the Snackbar.vue component
<template>
<div class="text-center">
<v-snackbar
transition="true"
bottom
right
v-model="show"
:color="snackbar.color"
:timeout="snackbar.timeout"
class="snackbar-shadow"
>
<div class="d-flex align-start alert-notify">
<v-icon size="24" class="text-white mr-5">{{ snackbar.icon }}</v-icon>
<p class="mb-0">
<span class="font-size-root font-weight-600">{{
snackbar.title
}}</span>
<br />
{{ snackbar.message }}
</p>
</div>
<template v-slot:action="{ attrs }">
<v-btn
icon
elevation="0"
max-width="136"
:ripple="false"
height="43"
class="font-weight-600 text-capitalize py-3 px-6 rounded-sm"
color="rgba(255,255,255, .85)"
text
v-bind="attrs"
#click="show = false"
>
<v-icon size="13">fas fa-times</v-icon>
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
name: "snackbar",
props: {
snackbar: Object,
},
computed: {
show: {
get() {
return this.snackbar.visible;
},
set(value) {
this.$emit("closeSnackbar", value);
},
},
},
};
</script>
Here is the App.vue component
<template>
<!-- Snackbar -->
<snackbar :snackbar="snackbar" #closeSnackbar="SnackbarClose"></snackbar>
</template>
<script>
export default {
name: "app",
data() {
return {
snackbar: {
visible: false,
timeout: 2000,
color: "#11cdef",
title: "Hello",
message: null,
icon: "fas fa-bell",
},
};
},
created: { this.SnackbarShow(); }
methods: {
SnackbarShow() {
this.snackbar.visible = true;
this.snackbar.message = "Hola!👋 I'm a snackbar";
},
SnackbarClose() {
this.snackbar.visible = false;
},
},
};
</script>