vue-form-wizard beforeTabChange callback not being called - vue.js

I have a simple three question onboarding form, I am trying to use the wizard for.
beforeTabSwitch does not appear to be called when I switch between the form elements. Here is my component:
<template>
<div>
...
<form-wizard #on-complete="onComplete">
<tab-content title="Location">
<p>looks like you're at {{address}}, correct?</p>
<b-form role="form" #submit.prevent="handleSubmit(login)">
<base-input alternative
class="mb-3"
name=""
:rules="{required: true}"
prepend-icon="ni ni-pin-3"
v-model="address">
</base-input>
</b-form>
</tab-content>
...
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</tab-content>
</form-wizard>
</div>
</template>
<script>
...
methods: {
onComplete: function(){
alert(this.$store.state.auth.userPrefs.genre);
},
beforeTabSwitch: function(){
alert("This is called before switching tabs")
return true;
}
}
}
</script>

Related

How to send props in Vue

I am quite new in vue so I haven't understood the logic completely. My question is I have ticket and ticketlist components. So I am not on my ticket list component I am creating some tickets data and I want to show them according to the ticket component. To make it more clear here is my ticketlist component:
<template>
<section class="tickets">
<div class="container">
<div class="row">
<div class="col-12 col-md-3 mb-3">
<Ticket v-for="ticket in tickets" :key="ticket.id" :product="ticket"/>
</div>
</div>
</div>
</section>
</template>
<script>
import Ticket from './Ticket'
export default {
components: {
Ticket
},
data() {
return {
tickets: [
{
id: 0,
category: "Einzelkarte",
price: "€3,50",
tariff: [
"Wählen Sie eine Option",
"Erwachsene",
"Erwachsener erm.",
"Kinder / Jugendliche",
"Kinder / Jugendliche erm.",
],
available_amount: 23,
article_number: "2021.05.04-2673990197-1",
},
],
};
},
}
</script>
And also ticket component:
<template>
<widget type="ticket" class="--flex-column">
<div class="top --flex-column">
<div class="bandname -bold">Ghost Mice</div>
<div class="tourname">Home Tour</div>
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/199011/concert.png" alt="" />
<div class="deetz --flex-row-j!sb">
<div class="event --flex-column">
<div class="date">3rd March 2017</div>
<div class="location -bold">Bloomington, Indiana</div>
</div>
<div class="price --flex-column">
<div class="label">Price</div>
<div class="cost -bold">€{{ ticket.price }}</div>
</div>
</div>
</div>
<div class="rip"></div>
<div class="bottom --flex-row-j!sb">
<a class="btn button" href="#">ADD TO CART</a>
</div>
</widget>
</template>
<script>
export default {
props: ['ticket'],
}
</script>
<style scoped>
#import 'https://i.koya.io/flex/1.1.0.css';
*, ::after, ::before {
box-sizing: unset;
}
</style>
So, I am showing TicketList component in one of the page but the thing is it doesnt show anything. So I wonder how can I connect them together and show tickets data according to ticket component. I hope I am clear but if I am not I can answer you in the comments.
The probleme is the props name, you need to pass ticket as props and not product
...
<Ticket v-for="ticket in tickets" :key="ticket.id" :ticket="ticket"/>
...
or the contrary inside you Ticket component set :
props: ['product']

PrimeVue Toast displaying html tags

How can I implement displaying a link in a primevue toast message? I cannot use v-html directive and triple brackets do not work. Does anybody has another idea how to solve it?
A hacky way is to extends Toast component:
Here a codesandbox : https://codesandbox.io/s/extend-primevue-toast-o5o1c?file=/src/CustomToastMessage.vue
1. On your component
Import your custom toast component where you need to call this.$toast:
<template>
<div>
<CustomToast />
<CustomToast position="top-left" group="tl" />
<CustomToast position="bottom-left" group="bl" />
<CustomToast position="bottom-right" group="br" />
<div class="card">
<Button #click="test" label="test" />
</div>
</div>
</template>
<script>
import CustomToast from "./CustomToast.vue";
export default {
components: {
CustomToast,
},
data() {
return {
messages: [],
};
},
methods: {
test() {
this.$toast.add({
severity: "success",
summary: "Test",
detail: "<b>Test Bold</b>",
});
},
},
};
</script>
2. CustomToast.vue (extend primevue toast)
<template>
<Teleport to="body">
<div ref="container" :class="containerClass" v-bind="$attrs">
<transition-group name="p-toast-message" tag="div" #enter="onEnter">
<CustomToastMessage
v-for="msg of messages"
:key="msg.id"
:message="msg"
#close="remove($event)"
/>
</transition-group>
</div>
</Teleport>
</template>
<script>
import Toast from "primevue/toast/Toast.vue";
import CustomToastMessage from "./CustomToastMessage.vue";
export default {
extends: Toast,
components: {
CustomToastMessage,
},
};
</script>
3. CustomToastMessage (extend primevue toastmessage)
Add v-html where you want to have html
<template>
<div
:class="containerClass"
role="alert"
aria-live="assertive"
aria-atomic="true"
>
<div class="p-toast-message-content">
<span :class="iconClass"></span>
<div class="p-toast-message-text">
<span class="p-toast-summary">{{ message.summary }}</span>
<div class="p-toast-detail" v-html="message.detail"></div>
</div>
<button
class="p-toast-icon-close p-link"
#click="onCloseClick"
v-if="message.closable !== false"
type="button"
v-ripple
>
<span class="p-toast-icon-close-icon pi pi-times"></span>
</button>
</div>
</div>
</template>
<script>
import ToastMessage from "primevue/toast/ToastMessage.vue";
export default {
extends: ToastMessage,
};
</script>
There is an easiest solution.
Just implement your own template.
Example:
<Toast :position="toastPosition">
<template #message="slotProps">
<span :class="iconClass"></span>
<div class="p-toast-message-text">
<span class="p-toast-summary">{{slotProps.message.summary}}</span>
<div class="p-toast-detail" v-html="slotProps.message.detail" />
</div>
</template>
</Toast>

How to transfer data between components (siblings) Vue?

In the HeaderComponent method 'clickPrices' is called on click
<template>
<header>
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<h5 class="my-0 mr-md-auto font-weight-normal">Company name</h5>
<nav class="my-2 my-md-0 mr-md-3">
<a class="p-2 text-dark" href="#">Features</a>
<a class="p-2 text-dark">Enterprise</a>
<a class="p-2 text-dark" #click="clickPrices()">Get pricing</a>
</nav>
<a class="btn btn-outline-primary " href="#">Sign up</a>
</div>
</header>
</template>
<script>
export default {
name: "HeaderComponent",
methods: {
clickPrices() {
...
},
},
}
</script>
<style scoped>
</style>
and there is a Pricing Component in which I make a request to the server in the method 'getPricing'
<template>
<div class="wrap-pricing">
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">Pricing</h1>
<p class="lead">Quickly build an effective pricing table for your potential customers with this Bootstrap example. It’s built with default Bootstrap components and utilities with little customization.</p>
</div>
<div class="container">
<div class="card-deck mb-3 text-center">
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h4 class="my-0 font-weight-normal">Lorem</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">$10 <small class="text-muted">/ mo</small></h1>
<ul class="list-unstyled mt-3 mb-4">
<li>Lorem</li>
<li>Lorem</li>
<li>Lorem</li>
<li>Lorem</li>
</ul>
<button type="button" class="btn btn-lg btn-block"></button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import router from '../routes.js';
import { axios } from 'axios';
export default {
name: "PriceComponent",
methods: {
getPricing() {
axios.get('api/pricing').then((response) => {
//some actions
router.push('prices');
});
},
},
}
</script>
<style scoped>
</style>
How should I process the result of the 'сlickPrices' HeaderComponent method?
Or am I waiting for your ways, how can I get data in another by clicking in one component
You can emit an event and let the parent component handle the fetching and pass the data as props to the child component.
Or another way is to directly listen to the event as follows
Component 1:
this.$root.$emit('clickPrices', data);
Component 2:
mounted() {
this.$root.$on('clickPrices', data => {
this.getPricing();
});
}
Check out the answer by #alex
Since you are using 2 independent components (one is not included in the other), you cannot pass props
Things you can do -
Instead of fetching all the prices on click, just create a created hook like so, which will fetch all the pricing details whenever your component is created -
created () {
this.getPricing()
},
methods: {
getPricing() {
axios.get('api/pricing').then((response) => {
//some actions
router.push('prices');
});
},
},
Use State and when a user clicks on the button, pricing details are fetched and added in the state. And you can just use the state anywhere in your application like so -
this.$store.state.prices
Let me know if it works, if not we will find some other solution for you!

How can I get value in select vue.js? vue.js 2

My case is like this
I have a component like this :
<template>
<div class="panel panel-default panel-filter">
...
<div id="collapse-location" class="collapse in">
<!-- province -->
<div style="margin-bottom: 10px">
<location-bs-select element-name="province_id" level="provinceList" type="1" module="searchByLocation"/>
</div>
<!-- city -->
<location-bs-select element-name="city_id" level="cityList" type="2" module="searchByLocation"/>
</div>
<!-- button search -->
<div class="panel-item">
<br>
<a href="javascript:;" class="btn btn-block btn-success" v-on:click="searchData">
Search
</a>
</div>
...
</div>
</template>
<script>
export default{
...
data() {
return{
...
province_id:'',
}
},
...
methods: {
...
searchData: function() {
console.log(this.province_id)
console.log(document.getElementsByName("province_id")[0].value)
console.log('testtt')
}
}
}
</script>
The component have child component, that is location-bs-select. The component used to display provincy and city
The component child like this :
<template>
<select class="form-control" v-model="selected" :name="elementName" #change="changeLocation">
<template v-for="option in options">
<template>
<option v-bind:value="option.id" >{{ option.name }}</option>
</template>
</template>
</select>
</template>
<script>
export default{
props: ['elementName', 'level','type','module'],
...
};
</script>
If I do inspect element, the result like this :
When click button search, I want to get the value of province and city
I try javascript like this :
console.log(document.getElementsByName("province_id")[0].value)
it works
But I want to use vue step. I try like this :
console.log(this.province_id)
It does not work
How can I solve it?
I hope I got you right. You want to propagate the value of the select back to the parent. The Child component COULD be like this.
removed template nesting
added change event listener and emit method
added data
And all together:
<template>
<select #change="emitChange" class="form-control" v-model="selected" :name="elementName">
<option v-for="option in options" v-bind:value="option.id" >{{ option.name }}</option>
</select>
</template>
<script>
export default{
props: ['elementName', 'level','type','module'],
data: function() {
return { selected: null }
},
methods: {
emitChange: function() {
this.$emit('changeval', this.selected);
}
}
};
</script>
Now your parent needs to listen to this emit. Here just the relevant parts of your parent
...
<location-bs-select element-name="city_id"
level="cityList"
type="2"
#changeval="changeval"
module="searchByLocation"/>
...
methods: {
changeval: function(sValue) {
this.province_id = sValue;
console.log(this.province_id);
}
}
Quickly summed up
the select value is bound to the selected prop of your data
the select has an attached change event which will emit changes
the parent will listen to this emit and will update it's relevant data prop

How can I get value in datetimepicker bootstrap on vue component?

My view blade, you can see this below :
...
<div class="panel-body">
<order-view v-cloak>
<input slot="from-date" data-date-format="DD-MM-YYYY" title="DD-MM-YYYY" type="text" class="form-control" placeholder="Date" name="from_date" id="datetimepicker" required>
<input slot="to-date" data-date-format="DD-MM-YYYY" title="DD-MM-YYYY" type="text" class="form-control" placeholder="Date" name="to_date" id="datetimepicker" required>
</order-view>
</div>
...
My order-view component, you can see this below :
<template>
<div>
<div class="col-sm-2">
<div class="form-group">
<slot name="from-date" required v-model="fromDate"></slot>
</div>
</div>
<div class="col-sm-1">
<div class="form-group" style="text-align: center">
-
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<slot name="to-date" required v-model="toDate"></slot>
</div>
</div>
<div class="col-sm-4">
<button v-on:click="filter()" class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</div>
</div>
</template>
<script>
export default {
data() {
return{
fromDate: '',
toDate: ''
}
},
methods: {
filter: function() {
console.log(this.fromDate)
console.log(this.toDate)
}
}
}
</script>
I using v-model like above code
But, when I click the button, the result of
console.log(this.fromDate)
console.log(this.toDate)
is empty
It display empty
Why it does not work?
How can I solve it?
You cannot bind a slot using v-model and expect that Vue will attach that automatically to your slot input, but I can't see any reason why you need to use a slot here anyway. It looks like you just want an input that you can attach custom attributes to and you can do that by passing the attributes as a prop and use v-bind to bind them:
<template>
<div>
<input v-bind="attrs" v-model="fromDate" />
<button #click="filter">filter</button>
</div>
</template>
export default{
props: ['attrs'],
methods: {
filter() {
console.log(this.fromDate)
}
},
data() {
return {
fromDate: ""
}
}
}
new Vue({
el: "#app",
data: {
fromDateAttrs: {
'data-date-format': "DD-MM-YYYY",
title: "DD-MM-YYYY",
type: "text",
class: "form-control",
placeholder: "Date",
name: "from_date",
id: "datetimepicker",
}
}
});
Now you can just pass your attrs as a prop in the parent:
<my-comp :attrs="fromDateAttrs"></my-comp>
Here's the JSFiddle: https://jsfiddle.net/rvederzc/
EDIT
In reference as to how to create a date picker component, here's how I would implement a jQuery datepicker using Vue.js:
<template id="date-picker">
<div>
<input v-bind="attrs" v-model="date" #input="$emit('input', $event.target.value)" v-date-picker/>
</div>
</template>
<script type="text/javascript">
export default {
props: ['attrs'],
directives: {
datePicker: {
bind(el, binding, vnode) {
$(el).datepicker({
onSelect: function(val) {
// directive talk for 'this.$emit'
vnode.context.$emit('input', val);
}
});
}
}
}
}
</script>
You can then bind that with v-model in the parent:
<date-picker v-model="myDate"></date-picker>
Here's the JSFiddle: https://jsfiddle.net/g64drpg6/
Cant expect any javascript technology to be complete before it becomes famous. Going by that, I tried all the recommendations from using moment to vue-datapicker. All recommendations heavily broke design and needed hardcode of the div id's in the vue initialisation under mounted. Cant introduce hacks into my project this way. Messes up design and implementation neatness.
I fixed it using plain old jsp. On Save, I just did this
vuedata.dateOfBirthMilliSecs = $("#dateOfBirth").val() ;
I'll figure out conversion of date format to milliseconds in my java controller.