1110 lines
42 KiB
Vue
Executable File
1110 lines
42 KiB
Vue
Executable File
<template>
|
|
<ClientOnly
|
|
><AppDoc name="StepsDemo" :sources="sources" :extPages="pages" github="steps/StepsDemo.vue">
|
|
<h5>Import via Module</h5>
|
|
<pre v-code.script><code>
|
|
import Steps from 'primevue/steps';
|
|
|
|
</code></pre>
|
|
|
|
<h5>Import via CDN</h5>
|
|
<pre v-code><code>
|
|
<script src="https://unpkg.com/primevue@^3/core/core.min.js"></script>
|
|
<script src="https://unpkg.com/primevue@^3/steps/steps.min.js"></script>
|
|
|
|
</code></pre>
|
|
|
|
<h5>MenuModel</h5>
|
|
<p>Steps uses the common MenuModel API to define the items, visit <router-link to="/menumodel">MenuModel API</router-link> for details.</p>
|
|
|
|
<h5>Getting Started</h5>
|
|
<p>Steps is integrated with Vue Router and requires a collection of menuitems as its model.</p>
|
|
<pre v-code><code>
|
|
<Steps :model="items" />
|
|
<router-view />
|
|
|
|
</code></pre>
|
|
|
|
<pre v-code.script><code>
|
|
export default {
|
|
data() {
|
|
return {
|
|
items: [{
|
|
label: 'Personal',
|
|
to: '/steps'
|
|
},
|
|
{
|
|
label: 'Seat',
|
|
to: '/steps/seat'
|
|
},
|
|
{
|
|
label: 'Payment',
|
|
to: '/steps/payment'
|
|
},
|
|
{
|
|
label: 'Confirmation',
|
|
to: '/steps/confirmation'
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
|
|
</code></pre>
|
|
|
|
<h5>Interactive</h5>
|
|
<p>Items are readonly by default, if you'd like to make them interactive then disable <i>readonly</i> property.</p>
|
|
<pre v-code><code>
|
|
<Steps :model="items" :readonly="false" />
|
|
<router-view />
|
|
|
|
</code></pre>
|
|
|
|
<h5>Templating</h5>
|
|
<p>Steps offers content customization with the <i>item</i> template that receives the menuitem instance from the model as a parameter.</p>
|
|
<pre v-code><code><template v-pre>
|
|
<Steps :model="items">
|
|
<template #item="{item}">
|
|
<a :href="item.url">{{item.label}}</a>
|
|
</template>
|
|
</Steps>
|
|
</template>
|
|
</code></pre>
|
|
|
|
<p><i>router-link</i> with route configuration can also be used within templating for further customization.</p>
|
|
<pre v-code><code><template v-pre>
|
|
<Steps :model="items">
|
|
<template #item="{item}">
|
|
<router-link :to="item.to" custom v-slot="{href, route, navigate, isActive, isExactActive}">
|
|
<a :href="href" @click="navigate" :class="{'active-link': isActive, 'active-link-exact": isExactActive}>{{route.fullPath}}</a>
|
|
</router-link>
|
|
</template>
|
|
</Steps>
|
|
</template>
|
|
</code></pre>
|
|
|
|
<h5>Properties</h5>
|
|
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
|
|
<div class="doc-tablewrapper">
|
|
<table class="doc-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Default</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>id</td>
|
|
<td>string</td>
|
|
<td>null</td>
|
|
<td>Unique identifier of the element.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>model</td>
|
|
<td>array</td>
|
|
<td>null</td>
|
|
<td>An array of menuitems.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>readonly</td>
|
|
<td>boolean</td>
|
|
<td>true</td>
|
|
<td>Whether the items are clickable or not.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>exact</td>
|
|
<td>boolean</td>
|
|
<td>true</td>
|
|
<td>Whether to apply 'router-link-active-exact' class if route exactly matches the item path.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h5>Slots</h5>
|
|
<div class="doc-tablewrapper">
|
|
<table class="doc-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Parameters</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>item</td>
|
|
<td>item: Menuitem instance</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h5>Styling</h5>
|
|
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
|
|
<div class="doc-tablewrapper">
|
|
<table class="doc-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Element</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>p-steps</td>
|
|
<td>Container element.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>p-steps-list</td>
|
|
<td>Root list element.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>p-steps-current</td>
|
|
<td>Current menuitem element.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>p-menuitem-link</td>
|
|
<td>Link element of the menuitem.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>p-steps-item</td>
|
|
<td>Menuitem element.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>p-steps-number</td>
|
|
<td>Number of menuitem.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>p-steps-title</td>
|
|
<td>Label of menuitem.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h5>Accessibility</h5>
|
|
<h6>Screen Reader</h6>
|
|
<p>
|
|
Steps component uses the <i>nav</i> element and since any attribute is passed to the root implicitly <i>aria-labelledby</i> or <i>aria-label</i> can be used to describe the component. Inside an ordered list is used where the current
|
|
step item defines <i>aria-current</i> as "step".
|
|
</p>
|
|
|
|
<h6>Keyboard Support</h6>
|
|
<div class="doc-tablewrapper">
|
|
<table class="doc-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Key</th>
|
|
<th>Function</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>
|
|
<i>tab</i>
|
|
</td>
|
|
<td>Adds focus to the active step when focus moves in to the component, if there is already a focused tab header then moves the focus out of the component based on the page tab sequence.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<i>enter</i>
|
|
</td>
|
|
<td>Activates the focused step if readonly is not enabled.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<i>space</i>
|
|
</td>
|
|
<td>Activates the focused step if readonly is not enabled.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<i>right arrow</i>
|
|
</td>
|
|
<td>Moves focus to the next step if readonly is not enabled.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<i>left arrow</i>
|
|
</td>
|
|
<td>Moves focus to the previous step if readonly is not enabled.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<i>home</i>
|
|
</td>
|
|
<td>Moves focus to the first step if readonly is not enabled.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<i>end</i>
|
|
</td>
|
|
<td>Moves focus to the last step if readonly is not enabled.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h5>Dependencies</h5>
|
|
<p>None.</p>
|
|
</AppDoc></ClientOnly
|
|
>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
sources: {
|
|
'options-api': {
|
|
tabName: 'Options API Source',
|
|
content: `
|
|
<template>
|
|
<div>
|
|
<Toast />
|
|
|
|
<div class="card">
|
|
<Steps :model="items" :readonly="true" aria-label="Form Steps" />
|
|
</div>
|
|
|
|
<router-view v-slot="{Component}" :formData="formObject" @prevPage="prevPage($event)" @nextPage="nextPage($event)" @complete="complete">
|
|
<keep-alive>
|
|
<component :is="Component" />
|
|
</keep-alive>
|
|
</router-view>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
items: [{
|
|
label: 'Personal',
|
|
to: '/'
|
|
},
|
|
{
|
|
label: 'Seat',
|
|
to: '/seat'
|
|
},
|
|
{
|
|
label: 'Payment',
|
|
to: '/payment'
|
|
},
|
|
{
|
|
label: 'Confirmation',
|
|
to: '/confirmation'
|
|
}],
|
|
formObject: {}
|
|
}
|
|
},
|
|
methods: {
|
|
nextPage(event) {
|
|
for (let field in event.formData) {
|
|
this.formObject[field] = event.formData[field];
|
|
}
|
|
|
|
this.$router.push(this.items[event.pageIndex + 1].to);
|
|
},
|
|
prevPage(event) {
|
|
this.$router.push(this.items[event.pageIndex - 1].to);
|
|
},
|
|
complete() {
|
|
this.$toast.add({severity:'success', summary:'Order submitted', detail: 'Dear, ' + this.formObject.firstname + ' ' + this.formObject.lastname + ' your order completed.'});
|
|
}
|
|
}
|
|
}
|
|
<\\/script>
|
|
|
|
<style scoped lang="scss">
|
|
::v-deep(b) {
|
|
display: block;
|
|
}
|
|
|
|
::v-deep(.p-card-body) {
|
|
padding: 2rem;
|
|
}
|
|
</style>
|
|
`
|
|
},
|
|
'composition-api': {
|
|
tabName: 'Composition API Source',
|
|
content: `<template>
|
|
<div>
|
|
<Toast />
|
|
|
|
<div class="card">
|
|
<Steps :model="items" :readonly="true" aria-label="Form Steps" />
|
|
</div>
|
|
|
|
<router-view v-slot="{Component}" :formData="formObject" @prevPage="prevPage($event)" @nextPage="nextPage($event)" @complete="complete">
|
|
<keep-alive>
|
|
<component :is="Component" />
|
|
</keep-alive>
|
|
</router-view>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { useToast } from 'primevue/usetoast';
|
|
|
|
export default {
|
|
setup() {
|
|
const router = useRouter();
|
|
const toast = useToast();
|
|
const items = ref([
|
|
{
|
|
label: 'Personal',
|
|
to: "/"
|
|
},
|
|
{
|
|
label: 'Seat',
|
|
to: "/seat",
|
|
},
|
|
{
|
|
label: 'Payment',
|
|
to: "/payment",
|
|
},
|
|
{
|
|
label: 'Confirmation',
|
|
to: "/confirmation",
|
|
}
|
|
]);
|
|
const formObject = ref({});
|
|
|
|
const nextPage = (event) => {
|
|
for (let field in event.formData) {
|
|
formObject.value[field] = event.formData[field];
|
|
}
|
|
|
|
router.push(items.value[event.pageIndex + 1].to);
|
|
};
|
|
const prevPage = (event) => {
|
|
router.push(items.value[event.pageIndex - 1].to);
|
|
};
|
|
const complete = () => {
|
|
toast.add({severity:'success', summary:'Order submitted', detail: 'Dear, ' + formObject.value.firstname + ' ' + formObject.value.lastname + ' your order completed.'});
|
|
};
|
|
|
|
return { items, formObject, nextPage, prevPage, complete }
|
|
}
|
|
}
|
|
<\\/script>
|
|
|
|
<style scoped lang="scss">
|
|
::v-deep(b) {
|
|
display: block;
|
|
}
|
|
|
|
::v-deep(.p-card-body) {
|
|
padding: 2rem;
|
|
}
|
|
</style>
|
|
`
|
|
},
|
|
'browser-source': {
|
|
tabName: 'Browser Source',
|
|
imports: `<script src="https://unpkg.com/vue-router@4.0.0/dist/vue-router.global.js"><\\/script>
|
|
<script src="https://unpkg.com/primevue@^3/steps/steps.min.js"><\\/script>
|
|
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
|
|
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>
|
|
<script src="https://unpkg.com/primevue@^3/card/card.min.js"><\\/script>
|
|
<script src="https://unpkg.com/primevue@^3/inputnumber/inputnumber.min.js"><\\/script>
|
|
<script src="https://unpkg.com/primevue@^3/inputmask/inputmask.min.js"><\\/script>
|
|
<script src="https://unpkg.com/primevue@^3/checkbox/checkbox.min.js"><\\/script>`,
|
|
content: `<div id="app">
|
|
<p-toast></p-toast>
|
|
|
|
<div class="card">
|
|
<p-steps :model="items" :readonly="true" aria-label="Form Steps"></p-steps>
|
|
</div>
|
|
|
|
<router-view v-slot="{Component}" :form-data="formObject" @prev-page="prevPage($event)" @next-page="nextPage($event)" @complete="complete">
|
|
<keep-alive>
|
|
<component :is="Component"></component>
|
|
</keep-alive>
|
|
</router-view>
|
|
</div>
|
|
|
|
<script type="module">
|
|
const { createApp, ref } = Vue;
|
|
const { useToast } = primevue.usetoast;
|
|
|
|
const App = {
|
|
setup() {
|
|
const toast = useToast();
|
|
const items = ref([
|
|
{
|
|
label: 'Personal',
|
|
to: "/"
|
|
},
|
|
{
|
|
label: 'Seat',
|
|
to: "/seat",
|
|
},
|
|
{
|
|
label: 'Payment',
|
|
to: "/payment",
|
|
},
|
|
{
|
|
label: 'Confirmation',
|
|
to: "/confirmation",
|
|
}
|
|
]);
|
|
const formObject = ref({});
|
|
|
|
const nextPage = (event) => {
|
|
for (let field in event.formData) {
|
|
formObject.value[field] = event.formData[field];
|
|
}
|
|
|
|
router.push(items.value[event.pageIndex + 1].to);
|
|
};
|
|
const prevPage = (event) => {
|
|
router.push(items.value[event.pageIndex - 1].to);
|
|
};
|
|
const complete = () => {
|
|
toast.add({severity:'success', summary:'Order submitted', detail: 'Dear, ' + formObject.value.firstname + ' ' + formObject.value.lastname + ' your order completed.'});
|
|
};
|
|
|
|
return { items, formObject, nextPage, prevPage, complete }
|
|
},
|
|
components: {
|
|
"p-steps": primevue.steps,
|
|
"p-toast": primevue.toast,
|
|
"p-card": primevue.card
|
|
}
|
|
};
|
|
|
|
const Personal = {
|
|
template: \`<div class="stepsdemo-content">
|
|
<p-card>
|
|
<template v-slot:title>
|
|
Personal Information
|
|
</template>
|
|
<template v-slot:subtitle>
|
|
Enter your personal information
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="p-fluid">
|
|
<div class="field">
|
|
<label for="firstname">Firstname</label>
|
|
<p-inputtext id="firstname" v-model="firstname" :class="{'p-invalid': validationErrors.firstname && submitted}"></p-inputtext>
|
|
<small v-show="validationErrors.firstname && submitted" class="p-error">Firstname is required.</small>
|
|
</div>
|
|
<div class="field">
|
|
<label for="lastname">Lastname</label>
|
|
<p-inputtext id="lastname" v-model="lastname" :class="{'p-invalid': validationErrors.lastname && submitted}"></p-inputtext>
|
|
<small v-show="validationErrors.lastname && submitted" class="p-error">Lastname is required.</small>
|
|
</div>
|
|
<div class="field">
|
|
<label for="age">Age</label>
|
|
<p-inputnumber id="age" v-model="age"></p-inputnumber>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<i></i>
|
|
<p-button label="Next" @click="nextPage()" icon="pi pi-angle-right" icon-pos="right"></p-button>
|
|
</div>
|
|
</template>
|
|
</p-card>
|
|
</div>\`,
|
|
data () {
|
|
return {
|
|
firstname: '',
|
|
lastname: '',
|
|
age: null,
|
|
submitted: false,
|
|
validationErrors: {}
|
|
}
|
|
},
|
|
methods: {
|
|
nextPage() {
|
|
this.submitted = true;
|
|
if (this.validateForm() ) {
|
|
this.$emit('next-page', {formData: {firstname: this.firstname, lastname: this.lastname, age: this.age}, pageIndex: 0});
|
|
}
|
|
},
|
|
validateForm() {
|
|
if (!this.firstname.trim())
|
|
this.validationErrors['firstname'] = true;
|
|
else
|
|
delete this.validationErrors['firstname'];
|
|
|
|
if (!this.lastname.trim())
|
|
this.validationErrors['lastname'] = true;
|
|
else
|
|
delete this.validationErrors['lastname'];
|
|
|
|
return !Object.keys(this.validationErrors).length;
|
|
}
|
|
},
|
|
components: {
|
|
"p-card": primevue.card,
|
|
"p-inputtext": primevue.inputtext,
|
|
"p-inputnumber": primevue.inputnumber,
|
|
"p-button": primevue.button
|
|
}
|
|
};
|
|
|
|
const Seat = {
|
|
template: \`<div class="stepsdemo-content">
|
|
<p-card>
|
|
<template v-slot:title>
|
|
Seat Information
|
|
</template>
|
|
<template v-slot:subtitle>
|
|
Choose your seat
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="p-fluid formgrid grid">
|
|
<div class="field col-12 md:col-6">
|
|
<label for="class">Class</label>
|
|
<p-dropdown input-id="class" v-model="selectedClass" :options="classes" @change="setWagons($event)" option-label="name" placeholder="Select a Class"></p-dropdown>
|
|
</div>
|
|
<div class="field col-12 md:col-6">
|
|
<label for="lastname">Wagon</label>
|
|
<p-dropdown input-id="wagon" v-model="selectedWagon" :options="wagons" @change="setSeats($event)" option-label="wagon" placeholder="Select a Wagon"></p-dropdown>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="seat">Seat</label>
|
|
<p-dropdown input-id="seat" v-model="selectedSeat" :options="seats" option-label="seat" placeholder="Select a Seat"></p-dropdown>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<p-button label="Back" @click="prevPage()" icon="pi pi-angle-left"></p-button>
|
|
<p-button label="Next" @click="nextPage()" icon="pi pi-angle-right" icon-pos="right"></p-button>
|
|
</div>
|
|
</template>
|
|
</p-card>
|
|
</div>\`,
|
|
data() {
|
|
return {
|
|
selectedClass: '',
|
|
classes: [
|
|
{name: 'First Class', code: 'A', factor: 1},
|
|
{name: 'Second Class', code: 'B', factor: 2},
|
|
{name: 'Third Class', code: 'C', factor: 3}
|
|
],
|
|
wagons: [],
|
|
selectedWagon: '',
|
|
seats: [],
|
|
selectedSeat: ''
|
|
}
|
|
},
|
|
methods: {
|
|
setWagons(event) {
|
|
if (this.selectedClass && event.value) {
|
|
this.wagons = [];
|
|
this.seats = [];
|
|
for (let i = 1; i < 3 * event.value.factor; i++) {
|
|
this.wagons.push({wagon: i + event.value.code, type: event.value.name, factor: event.value.factor});
|
|
}
|
|
}
|
|
},
|
|
setSeats(event) {
|
|
if (this.selectedWagon && event.value) {
|
|
this.seats = [];
|
|
for (let i = 1; i < 10 * event.value.factor; i++) {
|
|
this.seats.push({seat: i, type: event.value.type});
|
|
}
|
|
}
|
|
},
|
|
nextPage() {
|
|
this.$emit('next-page', {formData: {class: this.selectedClass.name, wagon: this.selectedWagon.wagon, seat: this.selectedSeat.seat}, pageIndex: 1});
|
|
},
|
|
prevPage() {
|
|
this.$emit('prev-page', {pageIndex: 1});
|
|
}
|
|
},
|
|
components: {
|
|
"p-card": primevue.card,
|
|
"p-dropdown": primevue.dropdown,
|
|
"p-button": primevue.button
|
|
}
|
|
};
|
|
|
|
const Payment = {
|
|
template: \`<div class="stepsdemo-content">
|
|
<p-card>
|
|
<template v-slot:title>
|
|
Payment Information
|
|
</template>
|
|
<template v-slot:subtitle>
|
|
Enter your card details
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="p-fluid formgrid grid">
|
|
<div class="field col-12">
|
|
<label for="class">Card Holder Name</label>
|
|
<p-inputtext type="text" v-model="cardholderName"></p-inputext>
|
|
</div>
|
|
<div class="field col-8">
|
|
<label id="number" for="lastname">Number</label>
|
|
<p-inputmask id="number" mask="9999-9999-9999-9999" v-model="cardholderNumber"></p-inputmask>
|
|
</div>
|
|
<div class="field col-2">
|
|
<label id="date" for="date">Date</label>
|
|
<p-inputmask id="date" mask="99/99" v-model="date"></p-inputmask>
|
|
</div>
|
|
<div class="field col-2">
|
|
<label for="cvv">CVV</label>
|
|
<p-inputmask id="cvv" mask="999" v-model="cvv"></p-inputmask>
|
|
</div>
|
|
<div class="field-checkbox col-12">
|
|
<p-checkbox id="remember" v-model="remember" :binary="true"></p-checkbox>
|
|
<label for="remember" class="p-checkbox-label">Save credit card information for future</label>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<p-button label="Back" @click="prevPage()" icon="pi pi-angle-left"></p-button>
|
|
<p-button label="Next" @click="nextPage()" icon="pi pi-angle-right" icon-pos="right"></p-button>
|
|
</div>
|
|
</template>
|
|
</p-card>
|
|
</div>\`,
|
|
data() {
|
|
return {
|
|
cardholderName:'',
|
|
cardholderNumber:'',
|
|
date:'',
|
|
cvv:'',
|
|
remember:false
|
|
}
|
|
},
|
|
methods: {
|
|
nextPage() {
|
|
this.$emit('next-page', {formData: {cardholderName: this.cardholderName, cardholderNumber: this.cardholderNumber, date: this.date, cvv: this.cvv}, pageIndex: 2});
|
|
},
|
|
prevPage() {
|
|
this.$emit('prev-page', {pageIndex: 2});
|
|
}
|
|
},
|
|
components: {
|
|
"p-card": primevue.card,
|
|
"p-inputtext": primevue.inputtext,
|
|
"p-inputmask": primevue.inputmask,
|
|
"p-checkbox": primevue.checkbox,
|
|
"p-button": primevue.button
|
|
}
|
|
};
|
|
|
|
const Confirmation = {
|
|
template: \`<div class="stepsdemo-content">
|
|
<p-card>
|
|
<template v-slot:title>
|
|
Confirmation
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="field col-12">
|
|
<label for="class">Name</label>
|
|
<b>{{formData.firstname ? formData.firstname : '-'}} {{formData.lastname ? formData.lastname : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Age</label>
|
|
<b>{{formData.age ? formData.age : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Seat Class</label>
|
|
<b>{{formData.class ? formData.class : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Wagon Number</label>
|
|
<b>{{formData.vagon ? formData.vagon : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Seat</label>
|
|
<b>{{formData.seat ? formData.seat : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Cardholder Name</label>
|
|
<b>{{formData.cardholderName ? formData.cardholderName : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Card Number</label>
|
|
<b>{{formData.cardholderNumber ? formData.cardholderNumber : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Date</label>
|
|
<b>{{formData.date ? formData.date : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">CVV</label>
|
|
<b>{{formData.cvv && formData.cvv.length === 3 ? '**' + formData.cvv[2] : '-'}}</b>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<p-button label="Back" @click="prevPage()" icon="pi pi-angle-left"></p-button>
|
|
<p-button label="Complete" @click="complete()" icon="pi pi-check" icon-pos="right" class="p-button-success"></p-button>
|
|
</div>
|
|
</template>
|
|
</p-card>
|
|
</div>\`,
|
|
props: {
|
|
formData: Object
|
|
},
|
|
methods: {
|
|
prevPage() {
|
|
this.$emit('prev-page', {pageIndex: 3});
|
|
},
|
|
complete() {
|
|
this.$emit('complete');
|
|
}
|
|
},
|
|
components: {
|
|
"p-card": primevue.card,
|
|
"p-button": primevue.button
|
|
}
|
|
};
|
|
|
|
const routes = [
|
|
{ path: "/", component: Personal },
|
|
{ path: "/seat", component: Seat },
|
|
{ path: "/payment", component: Payment },
|
|
{ path: "/confirmation", component: Confirmation }
|
|
];
|
|
|
|
const router = VueRouter.createRouter({
|
|
history: VueRouter.createWebHashHistory(),
|
|
routes
|
|
});
|
|
|
|
createApp(App)
|
|
.use(router)
|
|
.use(primevue.config.default)
|
|
.use(primevue.toastservice)
|
|
.mount("#app");
|
|
<\\/script>
|
|
|
|
<style>
|
|
b {
|
|
display: block;
|
|
}
|
|
|
|
.p-card-body {
|
|
padding: 2rem;
|
|
}
|
|
</style>
|
|
`
|
|
}
|
|
},
|
|
pages: [
|
|
{
|
|
tabName: 'PersonalDemo',
|
|
content: `
|
|
<template>
|
|
<div class="stepsdemo-content">
|
|
<Card>
|
|
<template v-slot:title>
|
|
Personal Information
|
|
</template>
|
|
<template v-slot:subtitle>
|
|
Enter your personal information
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="p-fluid">
|
|
<div class="field">
|
|
<label for="firstname">Firstname</label>
|
|
<InputText id="firstname" v-model="firstname" :class="{'p-invalid': validationErrors.firstname && submitted}" />
|
|
<small v-show="validationErrors.firstname && submitted" class="p-error">Firstname is required.</small>
|
|
</div>
|
|
<div class="field">
|
|
<label for="lastname">Lastname</label>
|
|
<InputText id="lastname" v-model="lastname" :class="{'p-invalid': validationErrors.lastname && submitted}" />
|
|
<small v-show="validationErrors.lastname && submitted" class="p-error">Lastname is required.</small>
|
|
</div>
|
|
<div class="field">
|
|
<label for="age">Age</label>
|
|
<InputNumber id="age" v-model="age" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<i></i>
|
|
<Button label="Next" @click="nextPage()" icon="pi pi-angle-right" iconPos="right" />
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data () {
|
|
return {
|
|
firstname: '',
|
|
lastname: '',
|
|
age: null,
|
|
submitted: false,
|
|
validationErrors: {}
|
|
}
|
|
},
|
|
methods: {
|
|
nextPage() {
|
|
this.submitted = true;
|
|
if (this.validateForm() ) {
|
|
this.$emit('next-page', {formData: {firstname: this.firstname, lastname: this.lastname, age: this.age}, pageIndex: 0});
|
|
}
|
|
},
|
|
validateForm() {
|
|
if (!this.firstname.trim())
|
|
this.validationErrors['firstname'] = true;
|
|
else
|
|
delete this.validationErrors['firstname'];
|
|
|
|
if (!this.lastname.trim())
|
|
this.validationErrors['lastname'] = true;
|
|
else
|
|
delete this.validationErrors['lastname'];
|
|
|
|
return !Object.keys(this.validationErrors).length;
|
|
}
|
|
}
|
|
}
|
|
<\\/script>
|
|
`
|
|
},
|
|
{
|
|
tabName: 'SeatDemo',
|
|
content: `
|
|
<template>
|
|
<div class="stepsdemo-content">
|
|
<Card>
|
|
<template v-slot:title>
|
|
Seat Information
|
|
</template>
|
|
<template v-slot:subtitle>
|
|
Choose your seat
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="p-fluid formgrid grid">
|
|
<div class="field col-12 md:col-6">
|
|
<label for="class">Class</label>
|
|
<Dropdown inputId="class" v-model="selectedClass" :options="classes" @change="setVagons($event)" optionLabel="name" placeholder="Select a Class" />
|
|
</div>
|
|
<div class="field col-12 md:col-6">
|
|
<label for="lastname">Wagon</label>
|
|
<Dropdown inputId="wagon" v-model="selectedVagon" :options="vagons" @change="setSeats($event)" optionLabel="vagon" placeholder="Select a Vagon" />
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="seat">Seat</label>
|
|
<Dropdown inputId="seat" v-model="selectedSeat" :options="seats" optionLabel="seat" placeholder="Select a Seat" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<Button label="Back" @click="prevPage()" icon="pi pi-angle-left" />
|
|
<Button label="Next" @click="nextPage()" icon="pi pi-angle-right" iconPos="right" />
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data () {
|
|
return {
|
|
selectedClass: '',
|
|
classes: [
|
|
{name: 'First Class', code: 'A', factor: 1},
|
|
{name: 'Second Class', code: 'B', factor: 2},
|
|
{name: 'Third Class', code: 'C', factor: 3}
|
|
],
|
|
vagons: [],
|
|
selectedVagon: '',
|
|
seats: [],
|
|
selectedSeat: ''
|
|
}
|
|
},
|
|
methods: {
|
|
setVagons(event) {
|
|
if (this.selectedClass && event.value) {
|
|
this.vagons = [];
|
|
this.seats = [];
|
|
for (let i = 1; i < 3 * event.value.factor; i++) {
|
|
this.vagons.push({vagon: i + event.value.code, type: event.value.name, factor: event.value.factor});
|
|
}
|
|
}
|
|
},
|
|
setSeats(event) {
|
|
if (this.selectedVagon && event.value) {
|
|
this.seats = [];
|
|
for (let i = 1; i < 10 * event.value.factor; i++) {
|
|
this.seats.push({seat: i, type: event.value.type});
|
|
}
|
|
}
|
|
},
|
|
nextPage() {
|
|
this.$emit('next-page', {formData: {class: this.selectedClass.name, vagon: this.selectedVagon.vagon, seat: this.selectedSeat.seat}, pageIndex: 1});
|
|
},
|
|
prevPage() {
|
|
this.$emit('prev-page', {pageIndex: 1});
|
|
}
|
|
}
|
|
}
|
|
<\\/script>
|
|
`
|
|
},
|
|
{
|
|
tabName: 'PaymentDemo',
|
|
content: `
|
|
<template>
|
|
<div class="stepsdemo-content">
|
|
<Card>
|
|
<template v-slot:title>
|
|
Payment Information
|
|
</template>
|
|
<template v-slot:subtitle>
|
|
Enter your card details
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="p-fluid formgrid grid">
|
|
<div class="field col-12">
|
|
<label for="class">Card Holder Name</label>
|
|
<InputText type="text" v-model="cardholderName" />
|
|
</div>
|
|
<div class="field col-8">
|
|
<label id="number" for="lastname">Number</label>
|
|
<InputMask id="number" mask="9999-9999-9999-9999" v-model="cardholderNumber" />
|
|
</div>
|
|
<div class="field col-2">
|
|
<label id="date" for="date">Date</label>
|
|
<InputMask id="date" mask="99/99" v-model="date" />
|
|
</div>
|
|
<div class="field col-2">
|
|
<label for="cvv">CVV</label>
|
|
<InputMask id="cvv" mask="999" v-model="cvv" />
|
|
</div>
|
|
<div class="field-checkbox col-12">
|
|
<Checkbox id="remember" v-model="remember" :binary="true" />
|
|
<label for="remember" class="p-checkbox-label">Save credit card information for future</label>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<Button label="Back" @click="prevPage()" icon="pi pi-angle-left" />
|
|
<Button label="Next" @click="nextPage()" icon="pi pi-angle-right" iconPos="right" />
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data () {
|
|
return {
|
|
cardholderName:'',
|
|
cardholderNumber:'',
|
|
date:'',
|
|
cvv:'',
|
|
remember:false
|
|
}
|
|
},
|
|
methods: {
|
|
nextPage() {
|
|
this.$emit('next-page', {formData: {cardholderName: this.cardholderName, cardholderNumber: this.cardholderNumber, date: this.date, cvv: this.cvv}, pageIndex: 2});
|
|
},
|
|
prevPage() {
|
|
this.$emit('prev-page', {pageIndex: 2});
|
|
}
|
|
}
|
|
}
|
|
<\\/script>
|
|
`
|
|
},
|
|
{
|
|
tabName: 'ConfirmationDemo',
|
|
content: `
|
|
<template>
|
|
<div class="stepsdemo-content">
|
|
<Card>
|
|
<template v-slot:title>
|
|
Confirmation
|
|
</template>
|
|
<template v-slot:content>
|
|
<div class="field col-12">
|
|
<label for="class">Name</label>
|
|
<b>{{formData.firstname ? formData.firstname : '-'}} {{formData.lastname ? formData.lastname : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Age</label>
|
|
<b>{{formData.age ? formData.age : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Seat Class</label>
|
|
<b>{{formData.class ? formData.class : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Wagon Number</label>
|
|
<b>{{formData.vagon ? formData.vagon : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Seat</label>
|
|
<b>{{formData.seat ? formData.seat : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Cardholder Name</label>
|
|
<b>{{formData.cardholderName ? formData.cardholderName : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Card Number</label>
|
|
<b>{{formData.cardholderNumber ? formData.cardholderNumber : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">Date</label>
|
|
<b>{{formData.date ? formData.date : '-'}}</b>
|
|
</div>
|
|
<div class="field col-12">
|
|
<label for="Age">CVV</label>
|
|
<b>{{formData.cvv && formData.cvv.length === 3 ? '**' + formData.cvv[2] : '-'}}</b>
|
|
</div>
|
|
</template>
|
|
<template v-slot:footer>
|
|
<div class="grid grid-nogutter justify-content-between">
|
|
<Button label="Back" @click="prevPage()" icon="pi pi-angle-left" />
|
|
<Button label="Complete" @click="complete()" icon="pi pi-check" iconPos="right" class="p-button-success"/>
|
|
</div>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
props: {
|
|
formData: Object
|
|
},
|
|
methods: {
|
|
prevPage() {
|
|
this.$emit('prev-page', {pageIndex: 3});
|
|
},
|
|
complete() {
|
|
this.$emit('complete');
|
|
}
|
|
}
|
|
}
|
|
<\\/script>
|
|
`
|
|
}
|
|
]
|
|
};
|
|
}
|
|
};
|
|
</script>
|