Created
May 1, 2018 16:39
-
-
Save OwenMelbz/49fea7873e1c6eab66b43e40bee237dd to your computer and use it in GitHub Desktop.
Simple Form with Floating Labels
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.input { | |
max-width: 100%; | |
padding: 5px 10px; | |
transition: border-color .2s ease; | |
border-radius: 0; | |
border-color: $black-1; | |
outline: none; | |
font-size: 16px; | |
-webkit-appearance: none; | |
&:focus { | |
border-color: $grey-2; | |
} | |
.has-errors & { | |
border-color: $pink-3; | |
} | |
} | |
.label { | |
padding: 7px 10px; | |
transform: translate(0); | |
transform-origin: top left; | |
transition: transform .3s ease; | |
font-size: 16px; | |
pointer-events: none; | |
.filled & { | |
transform: scale(.5) translate(-10px, -40px); | |
} | |
.has-errors & { | |
color: $pink-1; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="mt2 pb2"> | |
<form> | |
<div v-if="errorToDisplay" class="message-to-read bg-pink p1 mb4" style="padding: 10px;"> | |
{{ errorToDisplay }} | |
</div> | |
<div v-if="messageToDisplay" class="message-to-read bg-white mb4" style="padding: 10px;"> | |
{{ messageToDisplay }} | |
</div> | |
<div class="grid clearfix"> | |
<div class="width-12-12 width-6-12@m pr2@m" :class="{ filled: isFilled('name') || isFocused('name'), 'has-errors': hasErrors('name') }"> | |
<label for="your-name" class="absolute block label">Your name</label> | |
<input @blur="blurField()" @focus="focusField('name')" class="input width-12-12 border" id="your-name" name="your-name" autocomplete="name" v-model="formData.name" /> | |
</div> | |
<div class="width-12-12 width-6-12@m mt2 mt0@m" :class="{ filled: isFilled('email') || isFocused('email'), 'has-errors': hasErrors('email') }"> | |
<label for="your-email" class="absolute block label">Your email</label> | |
<input @blur="blurField()" @focus="focusField('email')" class="input width-12-12 border" id="your-email" name="your-email" autocomplete="email" type="email" v-model="formData.email" /> | |
</div> | |
<div class="mt2 width-12-12" :class="{ filled: isFilled('message') || isFocused('message'), 'has-errors': hasErrors('message') }"> | |
<label class="absolute block label" for="your-message">Your message</label> | |
<textarea @blur="blurField()" @focus="focusField('message')" class="block input width-12-12 border" id="your-message" name="your-message" v-model="formData.message" style="min-height: 150px"></textarea> | |
</div> | |
</div> | |
<div class="width-12-12 mt2 right-align@m"> | |
<button class="button border-none bg-none" type="submit" @click.prevent="submitForm"> | |
<span class="underline fs-3 fs-4@m weight-600"> | |
{{ buttonText() }} | |
</span> | |
</button> | |
</div> | |
</form> | |
</div> | |
</template> | |
<script> | |
const each = require('lodash.foreach'); | |
export default { | |
props: { | |
endpoint: { | |
type: String, | |
required: true, | |
}, | |
unknownErrorMessage: { | |
type: String, | |
default: 'Oh dear, something’s gone a bit wrong. Please email us on [email protected] instead, and we’ll get back to you very shortly.', | |
}, | |
}, | |
data() { | |
return { | |
busy: false, | |
formData: { | |
name: '', | |
email: '', | |
message: '', | |
_token: document.head.querySelector('meta[name="csrf-token"]').content, | |
}, | |
formErrors: {}, | |
focusedField: null, | |
errorToDisplay: null, | |
messageToDisplay: null, | |
} | |
}, | |
computed: { | |
formIsValid() { | |
return this.formData.name && this.formData.email && this.formData.message; | |
}, | |
}, | |
mounted() { | |
window.addEventListener('online', () => { | |
this.$nextTick(() => this.$forceUpdate()); | |
}); | |
window.addEventListener('offline', () => { | |
this.$nextTick(() => this.$forceUpdate()); | |
}); | |
}, | |
methods: { | |
buttonText() { | |
if (!navigator.onLine) { | |
return 'No internet detected' | |
} | |
if (this.busy) { | |
return 'Sending...'; | |
} | |
return 'Send your message'; | |
}, | |
blurField() { | |
this.focusedField = null; | |
}, | |
focusField(name) { | |
this.focusedField = name; | |
}, | |
isFocused(name) { | |
return this.focusedField == name; | |
}, | |
isFilled(field) { | |
return this.formData[field]; | |
}, | |
hasErrors(field) { | |
let found = false; | |
each(this.formErrors, (errorMessage, fieldName) => { | |
found = fieldName == field ? true : found; | |
}); | |
return found; | |
}, | |
submitForm() { | |
this.busy = true; | |
this.formErrors = {}; | |
this.errorToDisplay = null; | |
this.messageToDisplay = null; | |
axios.post(this.endpoint, this.formData) | |
.then(resp => { | |
this.busy = false; | |
if (typeof resp.data !== 'object') { | |
this.errorToDisplay = this.unknownErrorMessage; | |
return this.$nextTick(() => scrollToErrors.scrollNow()); | |
} | |
this.formData.message = ''; | |
this.messageToDisplay = resp.data.message; | |
try { | |
dataLayer.push({ | |
event: 'Short Enquiry Form', | |
eventCategory: 'Form Submit', | |
eventAction: 'Short Enquiry Form', | |
eventLabel: window.location.href, | |
eventValue: 1, | |
}); | |
} catch (err) { | |
console.log(err); | |
} | |
return this.$nextTick(() => scrollToErrors.scrollNow()); | |
}) | |
.catch(err => { | |
this.busy = false; | |
if (!err.response || err.response.status !== 422 || typeof err.response.data !== 'object') { | |
this.errorToDisplay = this.unknownErrorMessage; | |
return this.$nextTick(() => scrollToErrors.scrollNow()); | |
} | |
this.formErrors = err.response.data; | |
each(this.formErrors, errorMessage => { | |
if (!this.errorToDisplay) { | |
this.errorToDisplay = errorMessage; | |
} | |
}); | |
try { | |
dataLayer.push({ | |
event: 'Short Enquiry Form Failed', | |
eventCategory: 'Failed Form Submission', | |
eventAction: 'Short Enquiry Form Failed', | |
eventLabel: this.errorToDisplay, | |
eventValue: 1, | |
}); | |
} catch (err) { | |
console.log(err); | |
} | |
this.$nextTick(() => scrollToErrors.scrollNow()); | |
}); | |
}, | |
}, | |
}; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment