Ecommerce Developer
 
 

APIs & Plug-ins

Develop a Store Finder with the Google Maps API, Part 4

 

Many successful ecommerce businesses also sell through brick-and-mortar stores. Therefore, having location information on a website can help improve cross channel sales in some cases.

This tutorial is the fourth in a series on how to build a location-finding web application using the Google Maps API, PHP, JavaScript, Ajax, and, of course, HTML and CSS.

In Part 1, I laid the application's foundation with a MySQL database, some geocoding, and an SQL query that located the distance between points on a great circle. In Part 2, I used PHP to fetch the SQL query's response and transform that response into XML. I also started on the JavaScript, which will do a lot of the work in this application. Part 3 saw me start capture the user-submitted address, initialize the Google Maps API, and geocode the user's address, generating a longitude and latitude that I could use for my distance-finding calculations.

In this installment, I will make an asynchronous request to the server, collect the XML my PHP script will create, and parse the XML for use on my page. Effectively, this section will demonstrate Ajax.

I needed a subject for my locations application, so I decided to build it to find the nearest Dutch Bros. coffee location in my home state, Idaho. Dutch Bros. is a regional drive-through coffee chain (in several states not just Idaho) that also sells merchandise online.

Step No. 10: Make the Ajax Call

In Step No. 9 from Part 3, I created a new JavaScript function called nearStepTwo(). This function referenced two additional functions, which I have yet to write. The first of these will be called nearStepThree() and it is this function that will be responsible for making the Ajax call to my web server.

To understand this step, it is helpful to look back at nearStepTwo() before we look forward to this new function.

function nearStepTwo(){
	geocoder.geocode({'address': cusLoc.value}, function(results, status){
		if(status == google.maps.GeocoderStatus.OK){
			var latitude = results[0].geometry.location.b;
			var longitude = results[0].geometry.location.c;
			cusStartAddress = new google.maps.LatLng(latitude, longitude);
			nearStepThree('http://localhost/Test-scripts/dutch_bros/dutch-bros-form.php?latitude=' + latitude + '&longitude=' + longitude, function(data){nearStepFour(data)});
			
		}
		else{
			alert('geocoding error');
		}
	});	
}

The nearStepTwo function had three basic tasks: (1) It captured the user-supplied starting address—this is the location for which I want to find the nearest Dutch Bros; (2) It submitted that address to the Google Maps API for geocoding; and (3) It called nearStepThree(), passing a URL string containing the longitude and latitude for starting address and describing a callback function that the JavaScript should use after the Ajax call is made.

Now it is time to write nearStepThree().

function nearStepThree(url, callback){
	var request = window.ActiveXObject ?
		new ActiveXObject('Microsoft.XMLHTTP') :
		new XMLHttpRequest;
	request.onreadystatechange = function(){
		if(request.readyState == 4){
			callback(request.responseText, request.status);
		}
	};
	request.open('GET', url, true);
	request.send(null);
}

This function has three tasks. The first of these is to create a cross-browser Ajax request and store that request in a variable named request. Next, the function will connect to the PHP script that I wrote in Part 1 of this series using the URL created in nearStepTwo(). The URL includes the user submitted or starting address longitude and latitude, which the PHP script will use to find the nearest Dutch Bros. location. Finally, nearStepThree() waits for the PHP script to return XML results and then passes those results to the callback function, nearStepFour().

There is a lot going on here, so I am going to first break down what the application is doing and then next take nearStepThree() piece-by-piece.

Here is what is happening in the location-finding application.

  • The user types an address into the location finder and clicks submit.
  • My JavaScript captures the user-submitted address and sends it to the Google Maps API to get a longitude and latitude for the address.
  • With the longitude and latitude for the user-submitted or starting address, the JavaScript creates a URL that aims at my PHP script and passes the starting address's longitude and latitude.
  • Next, the JavaScript makes an Ajax call to the PHP script using the URL described above.
  • The PHP script collects the starting address's longitude and latitude and uses an SQL query and the Haversine formula to calculate the distance from the starting address to each Dutch Bros. location in Idaho.
  • The query then orders the Dutch Bros. locations, with the nearest one first.
  • The PHP script takes this list of Dutch Bros. locations and converts it to XML.
  • The PHP then passes the XML back to the JavaScript via the Ajax call and the ready state changes to "4," meaning that the task is complete.
  • The JavaScript captures the XML and passes it to the callback function as data.

So there are a lot of moving parts in the application. But turning my attention back to nearStepThree(), I want to break it down into its various sections.

First, I created the cross-browser Ajax call.

var request = window.ActiveXObject ?
		new ActiveXObject('Microsoft.XMLHTTP') :
		new XMLHttpRequest;

Toward the end of the function, I submitted the call. Notice that I am passing the url variable and setting the method to "GET."

request.open('GET', url, true);
	request.send(null);

In the middle portion of the function, I listen for a onreadystatechange event, using a conditional statement to determine if the event has been completed.

In ready state events, a "4" means that the task has been completed. A ready state of "3" is said to be "interactive," meaning that data is being transferred. A ready state of "2" means that the call has loaded, while "1" means it is loading. And finally a ready state of "0" means that nothing has started to happen, yet.

if(request.readyState == 4){
	callback(request.responseText, request.status);
}

Step No. 11: Parse the XML

With a completed Ajax call, I now have some XML stored as data. I am going to write the function nearStepFour to help process that XML into something that I can display on my page. Remember, I have chosen to use Ajax rather than reload the page. So from the user's perspective the page and URL will not have changed, but rather suddenly there will be map and store location information available.

With this in mind, it is important to understand that this new function has several tasks to complete beyond the initial transformation of the XML. So many, in fact, that I don't think it is a good idea to show you the entire function just yet. Rather, I am going to focus on those parts of the function that are used to process the XML, and I will add to nearStepFour() in the next couple of installments in this tutorial series.

The function declaration accepts the data passed from nearStepThree().

function nearStepFour(data){

Next, the function creates a variable, xml and assigns to the variable the results returned from a new function called parseXml(). The parseXml() function is a cross browser method for getting the XML from our Ajax call. I could have made it internal to the nearStepFour function. But by separating it, I can use it to parse other XML data if I ever want to add more features to my page later. In this sense, I am setting it up as a utility.

function parseXml(str){
	if(window.ActiveXObject){
		var doc = new ActiveXObject('Microsoft.XMLDOM');
		doc.loadXML(str);
		return doc;
	}
	else if(window.DOMParser){
		return (new DOMParser).parseFromString(str, 'text/xml');
	}
}

In nearStepFour(), I next create a variable to hold the array of Dutch Bros. locations described in the XML.

var eachStore = xml.documentElement.getElementsByTagName('store');

In Part 1, I wrote the PHP that created the XML file. As a refresher, you will notice that the PHP warped each entry in a "store" tag. Here is that PHP code.

while ($row = @mysqli_fetch_assoc($result)){
	$node = $dom->createElement("store");
	$newnode = $parnode->appendChild($node);
	$newnode->setAttribute("store_name", $row['store_name']);
	$newnode->setAttribute("street", $row['street_number']);
	$newnode->setAttribute("city", $row['city']);
	$newnode->setAttribute("state", $row['state']);
	$newnode->setAttribute("zip", $row['zip']);
	$newnode->setAttribute("latitude", $row['latitude']);
	$newnode->setAttribute("longitude", $row['longitude']);
	$newnode->setAttribute("distance", $row['distance']);
}

Notice that the element the PHP created ($node = $dom->createElement("store");) is called store. All of the other data is held as an attribute of "store." So that the variable eachStore in my JavaScript actually contains the store name, address, city, state, zip code, longitude, latitude, and distance from the starting address for each individual Dutch Bros. location.

To extract the individual attributes of each "store," I will use a for loop that cycles through the XML, creating a variable for each attribute that I want to capture.

for(var i = 0; i < eachStore.length; i++){
	var store = eachStore[i].getAttribute('store_name');
	var street = eachStore[i].getAttribute('street');
	var city = eachStore[i].getAttribute('city');
	var state = eachStore[i].getAttribute('state');
	var zip = eachStore[i].getAttribute('zip');
	var latitude = eachStore[i].getAttribute('latitude');
	var longitude = eachStore[i].getAttribute('longitude');
	var distance = eachStore[i].getAttribute('distance');

Still inside of the for loop, I create a new div element to be added to the page.

var storeInfo = document.createElement('div');

Next, I assign the new div element a unique id so that I can style each store's results individually in CSS.

storeInfo.id = 'store-info' + [i];

I also assign the innerHTML for the new div, placing the store information in an unordered list.

	storeInfo.innerHTML = '<ul><li>' + store + '</li><li>' + street + '</li><li>' + city + ', ' + state + ' '  + zip  + '</li></ul>';

Summing Up This Installment

In this tutorial, I made an Ajax call, collected a response, parsed that response, and prepared to add the results to the document object model (DOM).

In the forthcoming Part 5, I will do some basic testing. So far, I have not had a good way to debug the application since I had no output. Part 5 will be the first chance I will have had at testing my output. I will also start to generate the actual Google Map, showing the user the nearest location, and I will need to place custom Dutch Bros. markers on that map.

Related Articles

Search Terms

3 Comments

Rss-sm