Woohoo! I released my portfolio!
You can check it out here.
I will keep writing about the things I learned while building this website, but I was so excited about it, and just got it posted.
The next thing I worked on was building a contact form so that great recruiters can reach out to me with job offers.๐
The Vue Template
I first built the template for the form in Nuxt.
I created a ContactForm component so that I would be able to use the form in multiple places on the site if I want to in the future.
Here is the ContactForm template:
<template>
<div>
<!-- This shows a success message if the form was submitted correctly. -->
<div v-if="success" class="rounded bg-indigo-500 text-white text-lg p-4">
Great! Your message has been sent successfully. I will try to respond
quickly.
</div>
<form
v-else
v-on:submit.prevent="sendMessage"
class="grid grid-cols-1 gap-y-6"
>
<!-- Here an error is displayed if something goes wrong -->
<div v-if="errored" class="rounded bg-red-200 text-lg p-4">
Bummer, Something went wrong. Did you fill out all of the fields?
</div>
<div>
<label for="full_name" class="sr-only">Full name*</label>
<div class="relative rounded-md shadow-sm">
<input
v-model="name"
required
name="name"
id="full_name"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Full name*"
/>
</div>
</div>
<div>
<label for="email" class="sr-only">Email*</label>
<div class="relative rounded-md shadow-sm">
<input
required
v-model="email"
name="email"
id="email"
type="email"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Email*"
/>
</div>
</div>
<div>
<label for="phone" class="sr-only">Phone</label>
<div class="relative rounded-md shadow-sm">
<input
v-model="phone"
name="phone"
id="phone"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Phone"
/>
</div>
</div>
<div>
<label for="message" class="sr-only">Message</label>
<div class="relative rounded-md shadow-sm">
<textarea
required
v-model="message"
name="message"
id="message"
rows="4"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Message*"
></textarea>
</div>
</div>
<div class="">
<span class="inline-flex rounded-md shadow-sm">
<button
type="submit"
class="inline-flex justify-center py-3 px-6 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out"
>
{{ loading ? "Sending Message..." : "Submit" }}
</button>
</span>
</div>
</form>
</div>
</template>
The Vue Script Tag
As you might have noticed, I am using data attributes for the form input attributes:
export default {
data() {
return {
loading: false,
success: false,
errored: false,
name: "",
email: "",
phone: "",
message: "",
};
},
I also have the loading, success, and errored data attributes for when users submit the form and using those attributes to hide and show various HTML elements in the template as well as the form input attributes.
The last part of the Vue component is a method that actually submits the form to our Strapi API:
methods: {
sendMessage() {
this.loading = true;
this.$axios
.post("/messages", {
name: this.name,
email: this.email,
phone: this.phone,
message: this.message,
}).then(response => {
this.success = true
this.errored =false
})
.catch(error => {
this.errored = true
})
.finally(() => {
this.loading = false
});
},
}
This sends the form to the backend, waits for a response, and displays messages based on whether the response was a success or not.
The full ContactForm component is here:
<template>
<div>
<div v-if="success" class="rounded bg-indigo-500 text-white text-lg p-4">
Great! Your message has been sent successfully. I will try to respond
quickly.
</div>
<form
v-else
v-on:submit.prevent="sendMessage"
class="grid grid-cols-1 gap-y-6"
>
<div v-if="errored" class="rounded bg-red-200 text-lg p-4">
Bummer, Something went wrong. Did you fill out all of the fields?
</div>
<div>
<label for="full_name" class="sr-only">Full name*</label>
<div class="relative rounded-md shadow-sm">
<input
v-model="name"
required
name="name"
id="full_name"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Full name*"
/>
</div>
</div>
<div>
<label for="email" class="sr-only">Email*</label>
<div class="relative rounded-md shadow-sm">
<input
required
v-model="email"
name="email"
id="email"
type="email"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Email*"
/>
</div>
</div>
<div>
<label for="phone" class="sr-only">Phone</label>
<div class="relative rounded-md shadow-sm">
<input
v-model="phone"
name="phone"
id="phone"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Phone"
/>
</div>
</div>
<div>
<label for="message" class="sr-only">Message</label>
<div class="relative rounded-md shadow-sm">
<textarea
required
v-model="message"
name="message"
id="message"
rows="4"
class="form-input block w-full py-3 px-4 placeholder-gray-500 transition ease-in-out duration-150"
placeholder="Message*"
></textarea>
</div>
</div>
<div class="">
<span class="inline-flex rounded-md shadow-sm">
<button
type="submit"
class="inline-flex justify-center py-3 px-6 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out"
>
{{ loading ? "Sending Message..." : "Submit" }}
</button>
</span>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
loading: false,
success: false,
errored: false,
name: "",
email: "",
phone: "",
message: "",
};
},
methods: {
sendMessage() {
this.loading = true;
this.$axios
.post("/messages", {
name: this.name,
email: this.email,
phone: this.phone,
message: this.message,
}).then(response => {
this.success = true
this.errored =false
})
.catch(error => {
this.errored = true
})
.finally(() => {
this.loading = false
});
},
}
};
</script>
Sweet! Got the frontend done, but right now all we are going to see when we submit the form is an error message. That is because we haven't built the backend for accepting the form submission.
Look out for my next article on that!
Top comments (3)
Thanks for this
For sure!
I would recommend you use fabform for a static website forms backend.