How to convert a what3words address to a street address

We will convert a users input (with Auto Suggest) into a street address and allow them to choose the correct one.

  1. Introduction
  2. Prerequisites
  3. Setting up the HTML page
  4. Auto Suggest
  5. Converting a what3words address into a street address
  6. Displaying it all on a Woosmap Map
  7. Conclusion

Introduction

This guide will explain to you how to build the following integration:

This example is made to showcase how-to:

Prerequisites

You will need a Woosmap Public Key with both:

You can follow this tutorial to learn how set up your account,
And this one to learn about Woosmap API Keys domain restrictions.

Setting up the HTML page

We will create our index.html first, this will give us divs to display information to the user and later display the map.

The following is a basic html starting block:

HTML
        <!DOCTYPE html>
<html>
  <head>
    <title>Woosmap what3words address to street address Converter</title>
    <meta charset="UTF-8" />
  </head>
  <body>
    <div id="app">
      <div id="map"></div>

      <div class="addressDetails">
        <div class="info">
          <div class="words"></div>
          <div class="nearest"></div>
        </div>
        <div class="options"></div>
      </div>

      <div class="w3w-input-container">
        <div class="w3w-input">
          <input
            id="input"
            type="search"
            placeholder="Your what3words (e.g. filled.count.soap)"
            autocomplete="off"
          />
        </div>
        <div id="all-results-container">
          <div class="autosuggest-results-container">
            <div class="autosuggest-results-title">what3words results</div>
            <div class="autosuggest-results"></div>

            <div class="w3w-results-container">
              <div class="w3w-results"></div>
            </div>
          </div>
          <div class="address-list-container">
            <div class="autosuggest-results-title">
              Woosmap addresses results
            </div>
            <div class="address-list"></div>
          </div>
        </div>
      </div>
    </div>
    <script src="src/index.js"></script>
    <script src="https://sdk.woosmap.com/map/map.js?key=<YOUR_PUBLIC_API_KEY>&language=en"></script>
  </body>
</html>

    

You shall also need some styling for your integration. You can copy this CSS file to your local integration. We’ve also created a utils.js file which contains some shortcuts to display/hide some part of the UI.

Auto Suggest

Now that we have the visual part to display our results, we can create the JavaScript part. First lets create the function to Auto Suggest possible what3words addresses to the user. This feature works similarly to our Localities API Autocomplete feature.

javascript
        import {
  hideSection,
  displaySection, 
  clearSection,
  getAddressListContainer,
  getAllResultsContainer,
  convertToAddress,
  getAddressDetailsContainer,
  getAddressList,
  getResultsContainer,
  getInput,
} from "./utils.js";

function autosuggestW3W(input) {
  return fetch(
    `https://api.woosmap.com/what3words/autosuggest?key=${window.woosmap_key}&input=${input}&clip-to-country=GB,FR`
  ).then((response) => response.json());
}

async function displayW3wSuggestion(event) {
  const { value } = getInput();
  value.replace('"', '\\"').replace(/^\s+|\s+$/g, "");

  if ((value.match(/[.]/g) || []).length !== 2) {
    hideSection(getResultsContainer());
    hideSection(getAddressListContainer());
    return;
  }
    
  hideSection(getAddressListContainer());
  hideSection(getAddressDetailsContainer());
  displaySection(getAllResultsContainer());

  const results = document.querySelector(".autosuggest-results");
  window.marker.setMap(null);

  const { suggestions } = await autosuggestW3W(value);
  clearSection(results);

  const list = document.createElement("ul");
  if (suggestions) {
    suggestions.forEach((suggestion) => {
      const item = document.createElement("li");
      item.className = "suggestion";
      item.id = suggestion.rank;
      item.innerHTML = `<div class="words">${suggestion.words}</div><div class="nearest">Nearest place : ${suggestion.nearestPlace}</div>`;
      item.dataset.word = suggestion.words;
      item.onclick = () => {
        w3wClickCallback(suggestion);
      };
      list.appendChild(item);
    });
    results.appendChild(list);
  } else {
    const failed = document.createElement("div");
    failed.innerHTML = "Failed to load suggestions";
    results.appendChild(failed);
  }

  displaySection(getResultsContainer(), "flex");
}

function w3wClickCallback(suggestion) {
  document.querySelector(".words").innerHTML = suggestion.words;
  document.querySelector(
    ".nearest"
  ).innerHTML = `Nearest place : ${suggestion.nearestPlace}`;
  getInput().value = `///${suggestion.words}`;
  getPossibleAddress(suggestion.words);
}


    

The displayW3wSuggestion() works by first returning the state of the HTML page to normal. Then requests the /autosuggest endpoint. We also check the users input contains at least two . before sending the inputs. This is because the /autosuggest endpoint needs at least 2 words to work properly. From the response of the request a list of the suggestions is created and displayed. Listeners for a click event are added to each suggestion. These listeners set the input field value to the suggestion which was clicked and then call the getPossibleAddress() function which we will create in the next part.

Converting a what3words address into a street address

Now that we can retrieve a what3words address, we need to create the functions to transform it into possible street addresses.

javascript
        
function convertToAddress(words) {
  return fetch(
    `https://api.woosmap.com/what3words/convert-to-address?key=${window.woosmap_key}&words=${words}`
  ).then((response) => response.json());
}


async function getPossibleAddress(words) {
  hideSection(getResultsContainer());
  displaySection(getAddressListContainer());
  hideSection(getAddressDetailsContainer());
  clearSection(getAddressList());
  const { results } = await convertToAddress(words);
  if (results) {
    displayAddressList(results);
  }
}

function displayAddressList(addressDetails) {
  const addressListContainer = getAddressList();
  const addressList = document.createElement("ul");

  if (!Array.isArray(addressDetails) || addressDetails.length === 0) {
    const line = document.createElement("li");
    line.className = "not-found";
    line.innerHTML =
      "what3words address invalid or no street address found within 200m of its location.";
    addressList.appendChild(line);
  } else {
    addressDetails.forEach((address, index) => {
      const line = document.createElement("li");
      line.className = "address";
      line.addEventListener("click", (event) =>
        getAddressDetails(event.target, address.public_id)
      );
      line.innerHTML = `<span class='pin'></span>${address.formatted_address}`;
      addressList.appendChild(line);
      if (index === 0) {
        getAddressDetails(line, address.public_id);
      }
    });
  }
  addressListContainer.appendChild(addressList);
}

    

There is a lot more happening in this file. The main entrypoint is of course the function we called earlier getPossibleAddress(). This works in a similar way as before, we clear the state of the integration and then we make a request to the /convert-to-address endpoint. The response from this call is then displayed as a list of street address suggestions, each one of them containing a public_id. Use this public_id to request Localities details endpoint and retrieve geometry (lat/lng) and address components. You are now ready to display results on a map with a marker and populate the information container in the bottom right of the map.

javascript
        
function getDetail(publicId) {
  return fetch(
    `https://api.woosmap.com/localities/details/?key=${window.woosmap_key}&public_id=${publicId}`
  ).then((response) => response.json());
}

async function getAddressDetails(target, publicId) {
  if (window.selectedAddress) {
    window.selectedAddress.classList.remove("selected");
  }
  window.selectedAddress = target;
  window.selectedAddress.classList.add("selected");

  const detailResponse = await getDetail(publicId);

  const addressDetails = detailResponse.result;
  if (addressDetails) {
    createAddressMarker(addressDetails);
    fillAddressDetails(addressDetails);
    displaySection(getAddressDetailsContainer());
  }
}

    

The code above fetches the detailed data for the first address of the list in order to display it automatically on the map. The other addresses are fetched on click. Then we can fill the detailed information container using the full address information.

javascript
        function fillAddressDetails(addressDetails) {
  const detailsHTML = document.querySelector(".addressDetails .options");
  detailsHTML.innerHTML = "";

  if (addressDetails.street_public_id) {
    detailsHTML.innerHTML += `<p class='option-detail'><span class='option-detail-label'>Street public id :</span><span class='bold'>${addressDetails.street_public_id}</span></p>`;
  }

  if (addressDetails.formatted_address) {
    detailsHTML.innerHTML += `<p class='option-detail'><span class='option-detail-label'>Formatted_address :</span><span class='bold'>${addressDetails.formatted_address}</span></p>`;
  }
  if (addressDetails.types && addressDetails.types[0]) {
    detailsHTML.innerHTML += `<p class='option-detail'><span class='option-detail-label'>Type : </span><span class='bold'>${addressDetails.types[0].replace(
      "_",
      " "
    )}</span></p>`;
  }
  if (addressDetails.geometry) {
    const locationTypeString = addressDetails.geometry.location_type;
    if (locationTypeString) {
      detailsHTML.innerHTML += `<p class='option-detail'><span class='option-detail-label'>Location type :</span> <span class='bold'>${locationTypeString
        .replace("_", " ")
        .toLowerCase()}</span></p>`;
    }
    detailsHTML.innerHTML += `<div class='option-detail'><div><span class='option-detail-label'>Latitude :</span> <span class='bold'>${addressDetails.geometry.location.lat.toString()}</span></div><div><span class='option-detail-label'>Longitude : </span><span class='bold'>${addressDetails.geometry.location.lng.toString()}</span></div></div>`;
    if (addressDetails.address_components) {
      let compoHtml = "";
      addressDetails.address_components.forEach((compo) => {
        compoHtml += `<p class='option-detail'><span class='option-detail-label'>${compo.types[0]}:</span> <span class='bold'>${compo.long_name}</span></p>`;
      });
      detailsHTML.innerHTML += `<div class='address-components'><div class='title'>Address components</div><div>${compoHtml}</div>`;
    }
  }
}

    

Displaying it all on a Woosmap Map

Of course, it’s hard to put a marker on a Map without a Map, so the last Javascript file we need to create is src/index.js. In here we will initialise the input listener and create the Woosmap Map.

Creating a Woosmap Map is super easy…

javascript
        function initMap() {
  const mapElement = getMap();
  window.myMap = new woosmap.map.Map(mapElement, {
    center: {
      lat: 48.8534,
      lng: 2.3488
    },
    disableDefaultUI: true,
    gestureHandling: "greedy",
    zoom: 5,
    styles: {
      featureType: "poi",
      stylers: [{ visibility: "off" }]
    }
  });
  window.marker = new woosmap.map.Marker({
    clickable: true,
    icon: {
      url: "https://www.woosmap.com/images/marker.png",
      scaledSize: {
        height: 59,
        width: 37
      }
    }
  });
  window.selectedW3W = null;
}

function initUI() {
  getInput().addEventListener("input", debounce(displayW3wSuggestion, 200));
}

initMap();
initUI();

    

The listener on the input uses a debounce function to stop making multiple requests from quick user input. The panMap function centers the map on the address taken as parameter. The debounce and panMap functions are defined in the utils.js file.

Conclusion

Voilà, easily take your users what3words address and convert it into a street address.

We hope this how-to guide shows you the power of our partnership with what3words. This integration is a great example of how to use these APIs in a few different use cases. For example, taking users address quickly at checkout or to allow delivery drivers to take a what3words address but get an actual street address to route too.

Was this article helpful?
Have more questions? Submit a request