How To Use Google Maps With Vue - Js Apps - Better Programming - Medium
How To Use Google Maps With Vue - Js Apps - Better Programming - Medium
John Au-Yeung
Aug 31 · 20 min read
Vue.js is a great framework for building front-end web apps. It uses a component-based
architecture which makes organizing code easy. It allows you to use the latest features
JavaScript has to offer, which means writing code to build your apps is easier than ever.
Component-based architecture means that our front-end app consists of parts that are
nested within each other. One component that is often used in applications is Google
Maps. Developers have created a high-quality Google Maps component for Vue.js apps.
In this piece, we will build an address book app with Vue.js that has maps to display a
contact’s location with Google Maps. A contact form allows us to add and edit our
contacts and we can get and delete contacts.
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 1/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
To add Google Maps functionality to our app, we use the vue2-google-maps package.
To build our app, first, we need to set up a back end. To do this, we use a Node.js
package, called JSON Server, to run our back end. Once this is running, it provides us
with routes to save our contact entries from the front end.
Also, we have to get an API key to use the Google Maps API. To do this, go to
https://developers.google.com/maps/documentation/ and sign in to your Google
account by clicking the Sign In link at the top right.
Now, we can start building our app. To do this, install the Vue CLI by running:
We need an HTTP client, a Material Design library for making our app look good, and
the VeeValidate library. To do this, run npm i axios vee-validate vue-material vue2-
google-maps .
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 2/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
Axios is our HTTP client for communicating with the back end. Vue Material is our
Material Design library. vue2-google-maps is the Google Maps library that we’re going
to use.
Next, we create our components that we nest in our page components. To do this,
create a components folder in the project folder and, within it, create a file called
ContactForm.vue .
<template>
<div class="contact-form">
<div class="center">
<h1>{{editing ? 'Edit': 'Add'}} Contact</h1>
</div>
<form novalidate class="md-layout" @submit="save">
<md-field :class="{ 'md-invalid': errors.has('firstName') }">
<label for="firstName">First Name</label>
<md-input
name="firstName"
v-model="contact.firstName"
v-validate="'required'"
:disabled="sending"
/>
<span class="md-error" v-if="errors.has('firstName')">First
Name is required.</span>
</md-field>
<br />
<br />
/>
<span class="md-error" v-
if="errors.has('addressLineOne')">Address line 1 is required.</span>
</md-field>
<br />
<br />
<br />
<br />
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 4/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
v-if="errors.firstByRule('postalCode', 'required')"
>Postal Code is required.</span>
<span
class="md-error"
v-if="errors.firstByRule('postalCode', 'regex')"
>Postal Code is invalid.</span>
</md-field>
<br />
<br />
<br />
<br />
<md-field :class="{ 'md-invalid': errors.has('email') }">
<label for="email">Email</label>
<md-input
type="email"
name="email"
autocomplete="email"
v-model="contact.email"
:disabled="sending"
v-validate="'required|email'"
/>
<span class="md-error" v-if="errors.firstByRule('email',
'required')">Email is required.</span>
<span class="md-error" v-if="errors.firstByRule('email',
'email')">Email is invalid.</span>
</md-field>
<script>
import { COUNTRIES } from "@/helpers/exports";
import { contactMixin } from "@/mixins/contactMixin";
export default {
name: "ContactForm",
mixins: [contactMixin],
props: {
editing: Boolean,
contactId: Number
},
computed: {
isFormDirty() {
return Object.keys(this.fields).some(key =>
this.fields[key].dirty);
},
contacts() {
return this.$store.state.contacts;
}
},
data() {
return {
sending: false,
contact: {},
countries: COUNTRIES.map(c => c.name)
};
},
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 6/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
beforeMount() {
this.contact = this.contacts.find(c => c.id == this.contactId)
|| {};
},
methods: {
async save(evt) {
evt.preventDefault();
try {
const result = await this.$validator.validateAll();
if (!result) {
return;
}
if (this.editing) {
await this.updateContact(this.contact, this.contactId);
await this.getAllContacts();
this.$emit("contactSaved");
} else {
await this.addContact(this.contact);
await this.getAllContacts();
this.$router.push("/");
}
} catch (ex) {
console.log(ex);
}
},
async getAllContacts() {
try {
const response = await this.getContacts();
this.$store.commit("setContacts", response.data);
} catch (ex) {
console.log(ex);
}
},
getPostalCodeRegex() {
if (this.contact.country == "United States") {
return /^[0-9]{5}(?:-[0-9]{4})?$/;
} else if (this.contact.country == "Canada") {
return /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/;
}
return /./;
},
getPhoneRegex() {
if (["United States",
"Canada"].includes(this.contact.country)) {
return /^[2-9]\d{2}[2-9]\d{2}\d{4}$/;
}
return /./;
}
}
};
</script>
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 7/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.contact-form {
margin: 0 auto;
width: 90%;
}
</style>
In the file above, we have the contact form for adding and updating contacts in our
address book. It is where VeeValidate is used the most.
Notice that, in most input controls within the form tag, we have the v-validate prop.
This is where we specify what kind of input the control accepts.
required means that the form field is required. regex means we validate against a
specified regular expression. This allows for custom form validation where there are no
available built-in rules for VeeValidate, or when you need to validate the field
differently, depending on the value of another field.
getPhoneRegex() {
if (["United States", "Canada"].includes(this.contact.country)){
return /^[2-9]\d{2}[2-9]\d{2}\d{4}$/;
}
return /./;
}
It allows us to validate the number to see if it matches the North American telephone
format when we enter United States or Canada. Otherwise, we let people enter
whatever they want.
getPostalCodeRegex() {
if (this.contact.country == "United States") {
return /^[0-9]{5}(?:-[0-9]{4})?$/;
} else if (this.contact.country == "Canada") {
return /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/;
}
return /./;
}
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 8/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
This allows us to check for US zip codes and Canadian postal codes.
To display errors, we can check if errors exist for a form field, then display errors.
errors.has(‘firstName’) checks if the first name field meets the validation criteria that
we specified.
As we’re checking whether it’s filled in, there is only one possible error, so we can just
display the only error when errors.has(‘firstName’) returns true . For something
more complex, like phone, we have:
This allows us to check for each validation rule separately. For the phone number field,
we have to check if it’s filled in and if what’s filled in has a valid format. The
errors.firstByRule function allows us to do that.
Each property is a form field and each property of the this.fields object has a dirty
async save(evt) {
evt.preventDefault();
try {
const result = await this.$validator.validateAll();
if (!result) {
return;
}
if (this.editing) {
await this.updateContact(this.contact, this.contactId);
await this.getAllContacts();
this.$emit("contactSaved");
} else {
await this.addContact(this.contact);
await this.getAllContacts();
this.$router.push("/");
}
} catch (ex) {
console.log(ex);
}
},
We need evt.preventDefault() to stop the form from submitting the normal way, i.e.
without calling the Ajax code below.
If result is falsy, the form validation failed, so we run return to stop the rest of the
function from executing. Finally, if the form fields are all valid, we can submit.
As this form is used for both adding and editing contacts, we have to check which
action we’re doing. If we edit, we call await this.updateContact(this.contact,
If we are adding, we will redirect to the home page at the end by calling
this.$router.push(“/”); .
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 10/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
In Map.vue , we put:
<template>
<GmapMap :center="{lat, lng}" :zoom="15" style="width: 70vw;
height: 300px">
<GmapMarker
:position="google && new google.maps.LatLng(lat, lng)"
:clickable="true"
:draggable="true"
/>
</GmapMap>
</template>
<script>
import { gmapApi } from "vue2-google-maps";
export default {
name: "Map",
props: {
lat: Number,
lng: Number
},
computed: {
google: gmapApi
}
};
</script>
Next, we write some helper code. Create a folder, called helpers , and within it, make a
},
{ "name": "Latvia", "code": "LV" },
{ "name": "Lebanon", "code": "LB" },
{ "name": "Lesotho", "code": "LS" },
{ "name": "Liberia", "code": "LR" },
{ "name": "Libyan Arab Jamahiriya", "code": "LY" },
{ "name": "Liechtenstein", "code": "LI" },
{ "name": "Lithuania", "code": "LT" },
{ "name": "Luxembourg", "code": "LU" },
{ "name": "Macao", "code": "MO" },
{ "name": "Macedonia, The Former Yugoslav Republic of", "code":
"MK" },
{ "name": "Madagascar", "code": "MG" },
{ "name": "Malawi", "code": "MW" },
{ "name": "Malaysia", "code": "MY" },
{ "name": "Maldives", "code": "MV" },
{ "name": "Mali", "code": "ML" },
{ "name": "Malta", "code": "MT" },
{ "name": "Marshall Islands", "code": "MH" },
{ "name": "Martinique", "code": "MQ" },
{ "name": "Mauritania", "code": "MR" },
{ "name": "Mauritius", "code": "MU" },
{ "name": "Mayotte", "code": "YT" },
{ "name": "Mexico", "code": "MX" },
{ "name": "Micronesia, Federated States of", "code": "FM" },
{ "name": "Moldova, Republic of", "code": "MD" },
{ "name": "Monaco", "code": "MC" },
{ "name": "Mongolia", "code": "MN" },
{ "name": "Montenegro", "code": "ME" },
{ "name": "Montserrat", "code": "MS" },
{ "name": "Morocco", "code": "MA" },
{ "name": "Mozambique", "code": "MZ" },
{ "name": "Myanmar", "code": "MM" },
{ "name": "Namibia", "code": "NA" },
{ "name": "Nauru", "code": "NR" },
{ "name": "Nepal", "code": "NP" },
{ "name": "Netherlands", "code": "NL" },
{ "name": "Netherlands Antilles", "code": "AN" },
{ "name": "New Caledonia", "code": "NC" },
{ "name": "New Zealand", "code": "NZ" },
{ "name": "Nicaragua", "code": "NI" },
{ "name": "Niger", "code": "NE" },
{ "name": "Nigeria", "code": "NG" },
{ "name": "Niue", "code": "NU" },
{ "name": "Norfolk Island", "code": "NF" },
{ "name": "Northern Mariana Islands", "code": "MP" },
{ "name": "Norway", "code": "NO" },
{ "name": "Oman", "code": "OM" },
{ "name": "Pakistan", "code": "PK" },
{ "name": "Palau", "code": "PW" },
{ "name": "Palestinian Territory, Occupied", "code": "PS" },
{ "name": "Panama", "code": "PA" },
{ "name": "Papua New Guinea", "code": "PG" },
{ "name": "Paraguay", "code": "PY" },
{ "name": "Peru", "code": "PE" },
{ "name": "Philippines", "code": "PH" },
{ "name": "Pitcairn", "code": "PN" },
{ "name": "Poland", "code": "PL" },
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 14/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
This provides the countries that we reference in ContactForm.vue and the API key from
Google that we will use later.
Next, we add our mixin to manipulate the contacts by communicating with the back
end. We make a folder called mixins and create a file called contactMixin.js within it.
addContact(data) {
return axios.post(`${apiUrl}/contacts`, data);
},
updateContact(data, id) {
return axios.put(`${apiUrl}/contacts/${id}`, data);
},
deleteContact(id) {
return axios.delete(`${apiUrl}/contacts/${id}`);
}
}
}
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 16/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
This will let us include the functions in the methods object of the component object we
include, or mixin with, by putting it in the mixins array of our component object.
Similarly, we need another mixin for the API call to the Google Maps API.
We create a file called mapMixin.js within the same folder as contactMixin.js and put:
The function make a GET request to get the latitude and longitude from the address as
described in the Google documentation.
<template>
<div class="about">
<ContactForm :edit="false" />
</div>
</template>
<script>
// @ is an alias to /src
import ContactForm from "@/components/ContactForm.vue";
export default {
name: "ContactFormPage",
components: {
ContactForm
}
};
</script>
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 17/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
This displays the ContactForm component we created. We set the :edit prop to false
Next, we add the home page to display a list of contacts. In the views folder, we add a
file called HomePage.vue if it doesn’t already exist. Then, in there, we put:
<template>
<div class="home">
<div class="center">
<h1>Address Book Home</h1>
</div>
<md-table>
<md-table-row>
<md-table-head md-numeric>ID</md-table-head>
<md-table-head>First Name</md-table-head>
<md-table-head>Last Name</md-table-head>
<md-table-head>Address Line 1</md-table-head>
<md-table-head>Address Line 2</md-table-head>
<md-table-head>City</md-table-head>
<md-table-head>Country</md-table-head>
<md-table-head>Postal Code</md-table-head>
<md-table-head>Gender</md-table-head>
<md-table-head>Age</md-table-head>
<md-table-head>Email</md-table-head>
<md-table-head></md-table-head>
<md-table-head></md-table-head>
<md-table-head></md-table-head>
</md-table-row>
@click="removeContact(c.id)">Delete</md-button>
</md-table-cell>
</md-table-row>
</md-table>
<md-dialog :md-active.sync="showDialog">
<md-dialog-content>
<ContactForm
:editing="true"
:contactId="selectedContactId"
@contactSaved="selectedContactId = undefined; showDialog =
false"
/>
</md-dialog-content>
</md-dialog>
<md-dialog :md-active.sync="showMapDialog">
<md-dialog-title>Map</md-dialog-title>
<Map :lat='lat' :lng='lng' />
<md-dialog-actions>
<md-button class="md-primary" @click="showMapDialog =
false">Close</md-button>
</md-dialog-actions>
</md-dialog>
</div>
</template>
<script>
import { contactMixin } from "@/mixins/contactMixin";
import { mapMixin } from "@/mixins/mapMixin";
import ContactForm from "@/components/ContactForm.vue";
import Map from "@/components/Map.vue";
export default {
name: "HomePage",
mixins: [contactMixin, mapMixin],
components: {
ContactForm,
Map
},
props: {
editing: Boolean,
id: Number
},
computed: {
contacts() {
return this.$store.state.contacts;
}
},
data() {
return {
showDialog: false,
selectedContactId: undefined,
showMapDialog: false,
lat: 0,
lng: 0
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 19/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
};
},
beforeMount() {
this.getAllContacts();
},
methods: {
async getAllContacts() {
try {
const response = await this.getContacts();
this.$store.commit("setContacts", response.data);
} catch (ex) {
console.log(ex);
}
},
async removeContact(id) {
try {
await this.deleteContact(id);
await this.getAllContacts();
} catch (ex) {
console.log(ex);
}
},
async openMap(contact) {
try {
const address = `${contact.addressLineOne},
${contact.addressLineTwo}, ${contact.city}, ${contact.country}`;
const response = await this.getLatLng(address);
const loc = response.data.results[0].geometry.location
this.lat = loc.lat;
this.lng = loc.lng;
this.showMapDialog = true;
} catch (ex) {
console.log(ex);
}
}
}
};
</script>
<style scoped>
.md-dialog-container {
padding: 20px;
}
.md-content.md-table.md-theme-default {
width: 95%;
margin: 0 auto;
}
</style>
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 20/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
We get our contacts during page load by calling the this.getAllContacts function in
the beforeMount function.
Notice that we have this.getContacts function from our mixin. Mixins allow us to
reuse code.
Code in our mixins cannot have the same name as the functions in our methods objects
in our components because mixin functions hook straight into our methods as we
exported an object with the methods field in our mixin code.
In the table, we have a button to let us open the dialog box to display the map of the
location of the contact. We used the Map component that we added earlier by getting
the address of the contact and then getting the latitude and longitude from it.
Then, pass the latitude and longitude into the Map component, which can be used by
the Google Maps component to display the map.
props: {
editing: Boolean,
id: Number
}
This is where we check if the passed in props have the right type.
We only accept boolean for the editing prop and number for id . If we pass in
In App.vue , we add our menu and top bar by putting the following:
<template>
<div id="app">
<md-toolbar class="md-accent">
<md-button class="md-icon-button" @click="showNavigation =
true">
<md-icon>menu</md-icon>
</md-button>
<h3 class="md-title">Vee Validate Address Book App</h3>
</md-toolbar>
<md-drawer :md-active.sync="showNavigation" md-swipeable>
<md-toolbar class="md-transparent" md-elevation="0">
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 21/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
<md-list>
<md-list-item>
<router-link to="/">
<span class="md-list-item-text">Home</span>
</router-link>
</md-list-item>
<md-list-item>
<router-link to="/contact">
<span class="md-list-item-text">Add Contact</span>
</router-link>
</md-list-item>
</md-list>
</md-drawer>
<router-view />
</div>
</template>
<script>
export default {
name: "app",
data: () => {
return {
showNavigation: false
};
}
};
</script>
<style lang="scss">
.center {
text-align: center;
}
</style>
In main.js , we add our boilerplate code to include Vue Material and VeeValidate in our
app:
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 22/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
Vue.use(VeeValidate);
Vue.use(VueMaterial);
Vue.use(VueGoogleMaps, {
load: {
key: GOOGLE_API_KEY,
v: '3.26'
}
})
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Vue.use(Router)
In store.js , we put:
Vue.use(Vuex)
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 23/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
}
})
To store our contact in a place where all components can access it.
The store uses the Vuex library so that we have a this.$store object to call our
mutation with the this.$store.commit function and get the latest data from the store
via the computed property of our component object, like so:
contacts() {
return this.$store.state.contacts;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-
scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="//fonts.googleapis.com/css?
family=Roboto:400,500,700,400italic|Material+Icons">
<link rel="stylesheet" href="https://unpkg.com/vue-
material/dist/vue-material.min.css">
<link rel="stylesheet" href="https://unpkg.com/vue-
material/dist/theme/default.css">
<title>Vue Google Maps Address Book App</title>
</head>
<body>
<noscript>
<strong>We're sorry but vee-validate-tutorial-app doesn't work
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 24/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
</html>
Now we are ready to start our JSON server. Go to the project folder and run json-
server — watch db.json to start the server. It will allow us to call these routes without
any configuration:
GET /contacts
POST /contacts
PUT /contacts/1
DELETE /contacts/1
These are all the routes we need. Data will be saved to db.json of the folder that we’re
in, which should be our app’s project folder.
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 25/26
02/09/2019 How To Use Google Maps With Vue.js Apps - Better Programming - Medium
https://medium.com/better-programming/how-to-use-google-maps-with-vue-js-apps-93268bee7b3f 26/26