2
0
mirror of https://github.com/tenrok/vue-form-wizard.git synced 2026-06-22 07:00:32 +03:00

#4 Add support for error messages when doing async before change

Add color styles when before-change fails
This commit is contained in:
cristijora
2017-04-26 21:56:25 +03:00
parent 6cc79f9766
commit 49ab0f4548
5 changed files with 149 additions and 96 deletions
+7
View File
@@ -93,6 +93,13 @@ props: {
type: String, type: String,
default: '#e74c3c' //circle, border and text color default: '#e74c3c' //circle, border and text color
}, },
/***
* Is set to current step and text when beforeChange function fails
*/
errorColor: {
type: String,
default: '#8b0000'
},
/** /**
* Can take one of the following values: 'circle|square|tab` * Can take one of the following values: 'circle|square|tab`
*/ */
+21 -7
View File
@@ -1,13 +1,14 @@
<template> <template>
<div> <div>
<form-wizard @on-complete="onComplete" <form-wizard @on-complete="onComplete"
shape="circle" shape="square"
color="#e74c3c" color="gray"
@on-loading="setLoading" @on-loading="setLoading"
class="card"> @on-error="setError"
class="card" ref="wizard">
<tab-content title="Personal details" <tab-content title="Personal details"
:before-change="validateAsync"
route="/first" route="/first"
:before-change="validateAsync"
icon="ti-user"> icon="ti-user">
</tab-content> </tab-content>
<tab-content title="Additional Info" <tab-content title="Additional Info"
@@ -16,7 +17,6 @@
icon="ti-settings"> icon="ti-settings">
</tab-content> </tab-content>
<tab-content title="Last step" <tab-content title="Last step"
:before-change="validateAsync"
route="/third" route="/third"
icon="ti-check"> icon="ti-check">
</tab-content> </tab-content>
@@ -24,6 +24,9 @@
<router-view></router-view> <router-view></router-view>
</transition> </transition>
<div class="loader" v-if="loadingWizard"></div> <div class="loader" v-if="loadingWizard"></div>
<div v-if="error">
{{error}}
</div>
</form-wizard> </form-wizard>
</div> </div>
</template> </template>
@@ -34,7 +37,9 @@
name: 'app', name: 'app',
data () { data () {
return { return {
loadingWizard: false loadingWizard: false,
error: null,
count: 0
} }
}, },
methods: { methods: {
@@ -44,10 +49,19 @@
setLoading (value) { setLoading (value) {
this.loadingWizard = value this.loadingWizard = value
}, },
setError (error) {
this.error = error
},
validateAsync () { validateAsync () {
//simulating an error for the first time and a success for the second time
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
setTimeout(() => { setTimeout(() => {
resolve(true) if (this.count < 1) {
this.count ++
reject('Some custom error')
} else {
resolve(true)
}
}, 1000) }, 1000)
}) })
}, },
+85 -79
View File
@@ -1,89 +1,95 @@
.vue-tab-wizard{ .vue-tab-wizard, .vue-form-wizard {
padding-bottom:20px; padding-bottom: 20px;
.icon-circle{ .is_error {
font-size: 18px; border-color: $danger-states-color !important;
border: 3px solid $gray-input-bg; .icon-container {
border-radius: 50%; background: $danger-states-color !important;
font-weight: $font-weight-bold;
width: 70px;
height: 70px;
background-color: $white-color;
position: relative;
display:flex;
justify-content: center;
align-content: center;
&.square_shape{
border-radius: 0;
}
&.tab_shape{
width:100%;
min-width:100px;
height:40px;
border:none;
background-color: $gray-input-bg;
border-radius:0;
}
.icon-container{
display:flex;
justify-content: center;
flex:1;
border-radius: 40%;
&.square_shape,&.tab_shape{
border-radius:0;
}
}
.icon{
display:flex;
align-items: center;
justify-content: center;
}
} }
}
.tab-content{ .icon-circle {
min-height: 100px; font-size: 18px;
padding: 30px 20px 10px; border: 3px solid $gray-input-bg;
border-radius: 50%;
font-weight: $font-weight-bold;
width: 70px;
height: 70px;
background-color: $white-color;
position: relative;
display: flex;
justify-content: center;
align-content: center;
&.square_shape {
border-radius: 0;
} }
&.tab_shape {
.card-footer{ width: 100%;
padding: 0 20px; min-width: 100px;
height: 40px;
border: none;
background-color: $gray-input-bg;
border-radius: 0;
} }
.icon-container {
.wizard-header{ display: flex;
padding: 15px 15px 15px 15px; justify-content: center;
position: relative; flex: 1;
border-radius: 3px 3px 0 0; border-radius: 40%;
z-index: 3; &.square_shape, &.tab_shape {
text-align: center; border-radius: 0;
}
} }
.icon {
.wizard-title{ display: flex;
color: $card-black-color; align-items: center;
font-weight: $font-weight-light; justify-content: center;
margin: 0;
text-align:center;
} }
}
.category{ .tab-content {
font-size: 14px; min-height: 100px;
font-weight: 400; padding: 30px 20px 10px;
color: #9A9A9A; }
margin-bottom: 0px;
text-align: center;
}
.wizard-navigation{ .card-footer {
.progress-with-circle{ padding: 0 20px;
position: relative; }
top: 40px;
z-index: 50;
height: 4px;
.progress-bar{ .wizard-header {
box-shadow: none; padding: 15px 15px 15px 15px;
-webkit-transition: width .3s ease; position: relative;
-o-transition: width .3s ease; border-radius: 3px 3px 0 0;
transition: width .3s ease; z-index: 3;
} text-align: center;
} }
.wizard-title {
color: $card-black-color;
font-weight: $font-weight-light;
margin: 0;
text-align: center;
}
.category {
font-size: 14px;
font-weight: 400;
color: #9A9A9A;
margin-bottom: 0px;
text-align: center;
}
.wizard-navigation {
.progress-with-circle {
position: relative;
top: 40px;
z-index: 50;
height: 4px;
.progress-bar {
box-shadow: none;
-webkit-transition: width .3s ease;
-o-transition: width .3s ease;
transition: width .3s ease;
}
} }
}
} }
+34 -9
View File
@@ -14,19 +14,25 @@
<ul class="nav nav-pills"> <ul class="nav nav-pills">
<li v-for="(tab, index) in tabs" :class="{active:tab.active}"> <li v-for="(tab, index) in tabs" :class="{active:tab.active}">
<a href="" @click.prevent="navigateToTab(index)"> <a href="" @click.prevent="navigateToTab(index)">
<div class="icon-circle" :class="{checked:isChecked(index),square_shape:isStepSquare, tab_shape:isTabShape}" <div class="icon-circle"
:style="isChecked(index)? stepCheckedStyle : {}"> :class="{checked:isChecked(index),square_shape:isStepSquare, tab_shape:isTabShape}"
:style="[isChecked(index)? stepCheckedStyle : {}, tab.validationError ? errorStyle : {}]">
<transition :name="transition" mode="out-in"> <transition :name="transition" mode="out-in">
<div v-if="tab.active" class="icon-container" :class="{square_shape:isStepSquare, tab_shape:isTabShape}" <div v-if="tab.active" class="icon-container"
:style="tab.active ? iconActiveStyle: {}"> :class="{square_shape:isStepSquare, tab_shape:isTabShape}"
:style="[tab.active ? iconActiveStyle: {}, tab.validationError ? errorStyle : {}]">
<i v-if="tab.icon" :class="tab.icon" class="icon"></i> <i v-if="tab.icon" :class="tab.icon" class="icon"></i>
<i v-else class="icon">{{index + 1}}</i> <i v-else class="icon">{{index + 1}}</i>
</div> </div>
<i v-if="!tab.active && tab.icon" :class="tab.icon" class="icon"></i> <i v-if="!tab.active && tab.icon" :class="tab.icon" class="icon"></i>
<i v-if="!tab.active && !tab.icon" class="icon">{{index + 1}}</i> <i v-if="!tab.active && !tab.icon" class="icon">{{index + 1}}</i>
</transition> </transition>
</div> </div>
<span class="stepTitle" :style="tab.active ? stepTitleStyle : {}"> <span class="stepTitle"
:class="{active:tab.active, has_error:tab.validationError}"
:style="tab.active ? stepTitleStyle : {}">
{{tab.title}} {{tab.title}}
</span> </span>
@@ -104,6 +110,10 @@
type: String, type: String,
default: '#e74c3c' default: '#e74c3c'
}, },
errorColor: {
type: String,
default: '#8b0000'
},
shape: { shape: {
type: String, type: String,
default: 'circle' default: 'circle'
@@ -161,9 +171,16 @@
borderColor: this.color borderColor: this.color
} }
}, },
stepTitleStyle () { errorStyle () {
return { return {
color: this.color borderColor: this.errorColor,
backgroundColor: this.errorColor
}
},
stepTitleStyle () {
var isError = this.tabs[this.activeTabIndex].validationError
return {
color: isError ? this.errorColor : this.color
} }
}, },
isStepSquare () { isStepSquare () {
@@ -207,7 +224,12 @@
this.loading = value this.loading = value
this.$emit('on-loading', value) this.$emit('on-loading', value)
}, },
setValidationError (error) {
this.tabs[this.activeTabIndex].validationError = error
this.$emit('on-error', error)
},
validateBeforeChange (promiseFn, callback) { validateBeforeChange (promiseFn, callback) {
this.setValidationError(null)
// we have a promise // we have a promise
if (promiseFn.then && typeof promiseFn.then === 'function') { if (promiseFn.then && typeof promiseFn.then === 'function') {
this.setLoading(true) this.setLoading(true)
@@ -215,8 +237,9 @@
this.setLoading(false) this.setLoading(false)
let validationResult = res === true let validationResult = res === true
this.executeBeforeChange(validationResult, callback) this.executeBeforeChange(validationResult, callback)
}).catch(() => { }).catch((error) => {
this.setLoading(false) this.setLoading(false)
this.setValidationError(error)
}) })
// we have a simple function // we have a simple function
} else { } else {
@@ -228,6 +251,8 @@
this.$emit('on-validate', validationResult, this.activeTabIndex) this.$emit('on-validate', validationResult, this.activeTabIndex)
if (validationResult) { if (validationResult) {
callback() callback()
} else {
this.tabs[this.activeTabIndex].validationError = 'error'
} }
}, },
beforeTabChange (index, callback) { beforeTabChange (index, callback) {
@@ -254,6 +279,7 @@
this.activeTabIndex = newIndex this.activeTabIndex = newIndex
this.checkStep() this.checkStep()
this.tryChangeRoute(newTab) this.tryChangeRoute(newTab)
this.increaseMaxStep()
return true return true
}, },
tryChangeRoute (tab) { tryChangeRoute (tab) {
@@ -277,7 +303,6 @@
let cb = () => { let cb = () => {
if (this.activeTabIndex < this.tabCount - 1) { if (this.activeTabIndex < this.tabCount - 1) {
this.changeTab(this.activeTabIndex, this.activeTabIndex + 1) this.changeTab(this.activeTabIndex, this.activeTabIndex + 1)
this.increaseMaxStep()
} else { } else {
this.isLastStep = true this.isLastStep = true
this.$emit('finished') this.$emit('finished')
+2 -1
View File
@@ -33,7 +33,8 @@
}, },
data () { data () {
return { return {
active: false active: false,
validationError: null
} }
} }
} }