Build a Places App with Foursquare and Google Maps using Onsen UI and AngularJS

In this tutorial we are going to learn how to use the Foursquare API and Google Static Maps API to create a Places App with Onsen UI and AngularJS. In this app we will be able to search for a particular place and filter the results by food, shops and outdoor places. There will be also an integrated static map which will lead to the Google Website once clicked.

Foursquare API gives us access to a huge database of different venues from all around the world. It includes a rich variety of information such as the place’s addresses, popularity, tips and photos. The access to the API is available for free and provides an easy setup.

Google Static API makes easy to visualize a location on a map using integrated markers. These tools, combined with the power of Monaca and OnsenUI, enable us to build a Place App in almost no time!

The app is structured into three views. The main view enables the user to search for places using a simple input box. This information is fetched from the Foursquare API and displayed in an ons-list, which contains some ons-list-item elements. Furthermore, there is an ons-button in the ons-toolbar which leads to a filtered view. In the filter view, the user has the possibility to filter the place’s categories (Food, Shops and Outdoor). In the main view, the user can also click on a cell which will be directed to a the details viewpage. In the details page, a static map containing the places location is generated using the Google Static Maps API. Some additional information, like the opening hours, will be displayed too. An insite version of the app can be seen below. The code is freely available to download on GitHub.

Getting the API keys

Before getting started, we need to create two accounts for accessing the APIs: one for Foursquare, in order to access the places information, and one for Google’s Static Map API in order to be able to display the static map.

To get the API key from Foursquare, we first need to create an account on their website, click on “Create a new app” and fill in the details. At the new page, we will be granted with a Client ID and a Client Secret, both needed in order to be able to perform request to the API.

For getting the API key from Google, we have to visit Google Developers Console (with our Google account), create a new project and enable the access for the Google Static Map API. In the credentials section we can select a method to access to this API. In our case, we will restrict it to only from our GitHub gh-pages repository. For every request we will send to the Google Maps API, we need to attach the generated API key.

The Main View: JavaScript Part

Let’s have a look at the JavaScript part first. In our Angular scope we will need to save two pieces of information: The search string, whose value will be bound to the input content, and a state variable that indicates whenever the content is loading, which may not have results at all:

We start by implementing the search function. First, we need to figure out what kind of request we have to do in order to get the data we desire. According to the documentation, we will do a simple HTTP request which will return JSON data. The URL is in the form:

https://api.foursquare.com/v2/venues/explore/?near=Shibuya&venuePhotos=1&section=food&client_id=YZQZP1Q2HEJWMD5ZVBMIQD3VSZC1W4BQCCQTVFEPJWNHL0RK&client_secret=ORHPL2VKKHUTB3KTJVDTB4D20AXBRCFKWVL12EPQNJNDFYBX&v=20131124

The parameters are:

  • near: the place we want to look for. We will use the string in the textbox.
  • section: it will include the options for the filter (Shops, Cafe and Outdoors). Since we want this information to be persistent after the app has been closed, we will use LocalStorage to store the information.
  • client_id: the generated client ID from Foursquare.
  • client_secret: the generated secret from the Foursquare.
  • v: the version of the API that we are using.

In the search function, we will first change the variable state to isLoading and then read the filter options from the localStorage. Afterwards, the app will make an HTTP request using Angular $http core service. After the query will be executed, the variable state will be changed to noResults or loaded, depending on the returned output. If some data has been returned, it will be parsed from the returned JSON object.

Since we want to update the cells, once the user enters a different searchString, we need to keep track of the value of the variable searchString. We can do this by using Angular $watch function.

// in the main view controller ...
$scope.$watch('obj.searchString', function() {
$scope.search();
});

The Main View: HTML + CSS

The top of the main view page consists of an ons-toolbar and an input search box. The rest contains an ons-list and two div’s. The ons-list will contain the list of places while one of the divs will contain the no-results view and the other div the loading. Depending on the value of the variable state, the appropriate containers will be shown and the other containers will be hidden.

Each ons-list-item is responsible for representing a venue. The structure of the HTML consists mainly of a combination of ons-row and ons-col. For a better illustration, take a look at the image below.

Each list item consists of a single ons-row that contains itself three ons-col: the first column contains the photo of the place, the second displays important information about the place and the third column displays the chevron. The second column is splitted into four rows: the first one for the title, the second one for the rating, the reviews and the price, the third on for the address and the forth one for the category. Furthermore, we use ng-repeat to generate the right quantity of yellow and grey stars:

The style of the cells of the main view is pretty straightforward: most of the positioning is done by ons-row and ons-cell. The containing elements just need small adjustments. For more details, check out the GitHub Repo.

The more challenging part of the styling is the search box, which we want to stick to the view. Since iOS does not really support position: fixed, we need to use position: absolute and set the list-item-container height to 100%:

Furthermore, we need to style the chevron image since we created a custom image due to the bigger height of our cells.

Filter Page

The filter page consists in an ons-toolbar and an ons-list with 3 list items, which are the switches for the filter options: Food, Shop and Outdoors.

For the JavasScript part, we will load the filter options into the scope of our controller. Furthermore, the values of the switches will be set according to the value of the options. We need to also watch the sliders in order to adjust the values of the filter options.

Once the user clicks on either the cancel or the apply button, the navigation controller will pop the page. If the apply button is clicked, the filter options need to be saved in the localStorage and the main view controller needs to reload the data and initiate a search. To communicate between the controllers, we use a custom event. The main view controller will listen to the event and the filter view controller will fire it once the apply button has been clicked.

Details Page

In the details page we would like to display a static map of the location of the place. When clicked, it will bring us to the Google Maps website. Furthermore, we would like to show some additional information about this place. For our purpose the address and the opening hours are sufficient.

In order to get these information, we need to query the Foursquare API for details using a query like the following one:

https://api.foursquare.com/v2/venues/VENUE_ID?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&v=20131124

According to the documentation, the parameters are as following:

  • venue_id: the ID of the place.
  • client_id: the generated client ID from Foursquare.
  • client_secret: the generated secret from Foursquare.
  • v: the version of the API that we are using.

The venue ID is retrieved from the search query executed in the mainview controller. When we push the page, the ID is given as a parameter and used inside the details controller.

After reading the ID, a query to the API will be executed. After the query has finished, our application will parse the desired data out of the returned JSON object.

We are almost done! In order to finish the application, we need to layout and display the page. For the static map we will use Google Maps Static API. The URL of the image will be like the following one:

<img ng-src="https://maps.googleapis.com/maps/api/staticmap?zoom=16&size=640x3200&maptype=roadmap&markers=color:blue%7Clabel:S%7C{{lat}},{{lng}}&key=AIzaSyBGmoYFxRHlmsK6LUPiPLWkeh0ti6iw2i4" />

The parameters are:

  • zoom: the zoom factor of the image.
  • size: the dimension of the image.
  • lat: the latitude of the location.
  • lng: the longitude of the location.
  • key: our google API key.

For more information, please consult the documentation. Ones the map has been clicked, the full version of the map will be displayed in Google Maps webpage (or mobile app):

For the HTML part we only need to put the data together. First we have an img of the map abd an ons-list that contains the address and the opening hours. We will also use a scope variable to show the loading spinner, as long as the data has not been completely loaded.

Finally we are done!

Both the Foursquare API and the Google Static Map API enables us to do much more than what we have seen in this tutorial. For those who are interested, take a look at the documentations:

Conclusion

We have seen that it is relatively easy to build a Places App with OnsenUI, AngularJS, Foursquare API and Google Static Maps API. We invite you to play with the source code on Github and, if you have any question, don’t hesitate to ask in the comments, on Onsen GitHub issues or our new Community. More tutorials will be coming soon!