Vue.js + Places API: Build A Nearby Locations App

Last modified on April 17th, 2023
Raja Tamil
Google Maps API Vue.js

By the end of this tutorial, you will know how to build a simple app called CloseBuy that will get nearby places, such as restaurants, based on the user’s current location using Vue.js and Google Maps JavaScript API.

Also, I am going to cover how to add nearby locations to Google Maps.

Let’s take a look at our simple CloseBuy App below.

I assume that you already know:

Once the Vue project is up and running, create a page based component inside the pages folder called CloseBuy.vue and set a route for it.

As you can see, our final CloseBuy app has three UI View Components which are:

I could create three separate vue components for each UI module but for simplicity sake, I am going to put all the code in a single page based component.

User Input Form Using Semantic UI

Let’s create a two-column grid layout with a Semantic UI CSS framework.

Here is the CDN link for it.

In the CloseBuy.vue component, add the following code in between the template tags.

<template>
  <div class="ui grid">
    <div class="six wide column"></div>
    <div class="ten wide column segment ui" ref="map"></div>
  </div>
</template>

Inside the left column, add HTML Markup for the User Input Form module.

<div class="six wide column">
    <form class="ui segment large form">
      <div class="ui segment">
        <div class="field">
          <div class="ui right icon input large">
            <input type="text" placeholder="Enter your address" v-model="coordinates" />
            <i class="dot circle link icon" @click="locatorButtonPressed"></i>
          </div>
        </div>
        <div class="field">
          <div class="two fields">
            <div class="field">
              <select v-model="type">
                <option value="restaurant">Restaurant</option>
              </select>
            </div>
            <div class="field">
              <select v-model="radius">
                <option value="5">5 KM</option>
                <option value="10">10 KM</option>
                <option value="15">15 KM</option>
                <option value="20">20 KM</option>
              </select>
            </div>
          </div>
        </div>
        <button class="ui button" @click="findCloseBuyButtonPressed">Find CloseBuy</button>
      </div>
    </form>
</div>

As you can see in the template, User Input Form has three main elements with the class field, which are:

  • Input field with locator icon button on the right.
  • Type field which is a drop-down list with a single option restaurant.
  • Radius field which is also a drop-down list with a few options.

The input field is bound to coordinates computed property and the locator button has a click event with a callback function locatorButtonPressed.

Type and Radius drop-down elements are bound to type and radius properties respectively in the data() model.

data() {
    return {
      lat: 0,
      lng: 0,
      type: "",
      radius: "",
      places: []
    };
},
computed: {
    coordinates() {
      return `${this.lat}, ${this.lng}`;
    }
}

Now, I am going to get the user’s location in the form of geographic coordinates when the locator button is pressed.

So, inside methods object, declare locatorButtonPressed() function.

methods: {
  locatorButtonPressed() {
    navigator.geolocation.getCurrentPosition(
      position => {
        this.lat = position.coords.latitude;
        this.lng = position.coords.longitude;
      },
      error => {
        console.log("Error getting location");
      }
    );
  }
}

I use HTML5 Geolocation API to get the geographic coordinates.

So, invoke getCurrentPosition() method on the geolocation object and get latitude and longitude values from the position object.

Then, assign them to the lat and lng properties that are declared in the data() model.

At this stage, the coordinates computed property will be set and you can see the values in the input field.

You can convert latitude and longitude values to an actual human readable street address using Google’s Geolocation.

Vue.js + Google Maps API: Get User Location [Street Address]

Finally, attach a click event to the “Find CloseBuy” button with a callback function called findCloseBuyButtonPressed and declare it inside the methods object.

This is where I am going to make an HTTP call to get the nearby places using Nearby Search Request.

Nearby Search Request is part of Google Places API and it lets us get nearby places based on:

  • User’s location in the form of Latitude and Longitude
  • Type (restaurant, bar, etc)
  • Radius

To make an HTTP request, install Axios to the Vue project which is an HTTP Client.

npm install axios --save

Then, import Axios at the top.

import axios from "axios";

Inside findCloseBuyButtonPressed() function, I have added the CORS Heroku link in front of Nearby Search BASE URL to avoid the CORS issue.

Then, make an HTTP request by running get() method on the Axios object with the URL as an argument.

findCloseBuyButtonPressed() {
	const URL = `https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${
        this.lat
      },${this.lng}&type=${this.type}&radius=${this.radius *
        1000}&key=[YOURAPIKEY]`;
	axios.get(URL).then(response => {
		this.places = response.data.results;
		this.addLocationsToGoogleMaps();
	}).catch(error => {
		console.log(error.message);
	});
},

The Nearby Search Request URL will take four required query parameters that are:

  • location: Latitude and longitude separated by a comma.
  • type: Restaurants, bars etc. you can find a full type list here.
  • radius: The unit must be in meters. So the value will be 5000 if it’s a 5KM range.
  • key: Your API Key from Google Cloud Platform.

The response object will have up to 20 places in the form of an array of objects. Assign it to the property called places that are defined in the data() model.

Places API offers getting places/locations based on Text Search as well.

Places API: Get Places By Text Search

Show Places List

Once we have an array of place objects, we can show them in the left column in a list format under the user input form.

To show the places, add the following HTML immediately after the ending </form> tag.

<div class="ui segment"  style="max-height:500px;overflow:scroll">
    <div class="ui divided items">
        <div class="item" v-for="place in places" :key="place.id">
            <div class="content">
                <div class="header">{{place.name}}</div>
                <div class="meta">{{place.vicinity}}</div>
            </div>
        </div>
    </div>
</div>

Loop through the places array using v-for and display the location name and address on each iteration.

And, the view will look like this.

If you want to get more information about each place such as hours, phone number etc, you will need to use the Place Details Request which is a part of Places API as well.

Add Locations To Google Maps

Call showPlacesOnMap() function where we get a response from Nearby Search Request.

Inside the function, create an instance of the Google Maps map object and assign it to the variable map.

addLocationsToGoogleMaps() {
	var map = new google.maps.Map(this.$refs['map'], {
		zoom: 15,
		center: new google.maps.LatLng(this.lat, this.lng),
		mapTypeId: google.maps.MapTypeId.ROADMAP
	});
	this.places.forEach((place) => {
		const lat = place.geometry.location.lat;
		const lng = place.geometry.location.lng;
		let marker = new google.maps.Marker({
			position: new google.maps.LatLng(lat, lng),
			map: map
		});
	});
}

Then, loop through places array using forEach higher-order function.

I use forEach loop instead of for loop to avoid variable scope issue.

Inside each iteration, create a new instance of the marker object with a couple of parameters.

  • position: The location in the form of latitude and longitude that you want to pin the marker into on the map.
  • map: The map that you want to add the marker.

And, you can see all the markers showing on the maps.

Nice!

Let’s add a click event to each one of the markers to show the Info Window with some content in it.

First, create an instance of the InfoWindow() object above the forEach loop.

var infowindow = new google.maps.InfoWindow();

Inside the loop, attach a click event to each marker by calling the addListener() method on the event object.

google.maps.event.addListener(marker, "click", () => {
	infowindow.setContent(`<div class="ui header">${place.name}</div><p>${place.vicinity}</p>`);
	infowindow.open(map, marker);
});

In the click event callback function, add location name and address by invoking setContent() method on the InfoWindow object.

Finally, use open() method to display the Info Window by passing two arguments that are map and marker.

There you have it.