One place for hosting & domains

      Generate

      All the Ways to Generate a Next.js Site


      How to Join

      This Tech Talk is free and open to everyone. Register on Eventbrite here to receive a link to join on Wednesday, January 27, 2021, 11:30 a.m.–12:30 p.m. ET.

      About the Talk

      Next.js is an amazing tool that lets us build sites quickly. It handles things like routing, lazy loading, and image optimization. Learn how Next.js allows us to build the fastest possible site.

      What You’ll Learn

      • How Next.js features help us build the fastest possible blogs, websites, and applications
      • Using Incremental Static Generation to update static content after you have built your site
      • Grabbing data from an API

      This Talk is Designed For

      React developers that are looking to streamline your workflow.

      About the Presenter

      Chris Sev is a Senior Developer Advocate at DigitalOcean and the founder of scotch.io. He builds fullstack apps with JavaScript and puts a focus on building businesses.

      To join the live Tech Talk, register here.



      Source link

      How To Generate a Vue.js Single Page App With the Vue CLI


      The author selected Open Sourcing Mental Illness to receive a donation as part of the Write for DOnations program.

      Introduction

      Vue.js is a popular JavaScript framework for creating user interfaces. Created in 2014 by Evan You (formally of Google), Vue.js is often described as a combination of React and Angular, borrowing the prop-driven development of React and the templating power of Angular. This makes Vue an accessible framework for beginners to pick up, especially since it focuses on traditional HTML and CSS, rather than being a CSS-in-JS framework like React or relying on TypeScript (a superset of JavaScript) like Angular does.

      When starting a new project, it’s best to familiarize yourself with the technology’s tools and features. One important tool for Vue.js development is its command line interface (CLI) known as Vue CLI 3. The Vue CLI offers a number of useful features that enhance the Vue development experience, but the main feature is its ability to generate and pre-configure a new single-page application with the vue create command.

      By the end of this tutorial, you will have a working Vue.js application running on a local Node server. This local server uses hot module reloading via Webpack to provide immediate feedback, rendered in-browser as you work. Along the way, you will create .vue single-file components (SFC), such as a header and a footer. All of this you can save as a solid foundation for any future Vue projects.

      Prerequisites

      To follow this tutorial, you will need the following:

      Step 1 — Downloading Vue CLI 3

      To download Vue CLI 3, you will need to run a command either via npm or Yarn, whichever you prefer. npm or Node Package Manager is a way to download and manage other people’s code to use in your project as a dependency. Yarn, on the other hand, executes NPM commands under the hood but provides additional features like caching. It’s up to personal preference regarding which one to use. However, it is important to note that it’s not recommended to mix commands. It’s best to be consistent with one or the other for the duration of your project.

      Moving forward, this tutorial will use npm commands. The following command will download the necessary Vue CLI files from the registrar, which in this case is the npm (Node Package Manager) service:

      npm i -g @vue/cli
      

      Note: On some systems, installing an npm package globally can result in a permission error, which will interrupt the installation. Since it is a security best practice to avoid using sudo with npm install, you can instead resolve this by changing npm’s default directory. If you encounter an EACCES error, follow the instructions at the official npm documentation.

      You install this globally in order to use the CLI anywhere on your machine. If you don’t install this globally, it will only work in the directory that you installed it at. In the case of the command options, i means “install” and -g is a flag to install the code globally on your computer.

      To verify if Vue CLI 3 was properly installed, run the following:

      vue --version
      

      You will receive the following output with a version number. Your version number may differ, but if you receive a response with a version number, you’ve properly installed Vue CLI 3:

      Output

      @vue/cli 4.5.6

      To update Vue CLI 3, run the previous commands in this section, and the latest version will be installed.

      At this point, you have successfully downloaded npm globally along with the Vue CLI tool that you will use in the next section to create a generated Vue.js project.

      Step 2 — Generating a Single-Page Application

      As you develop Vue.js applications, you may find that manually configuring a project is not the most productive use of your time, since configuring a new Vue.js project from scratch can take hours. This is the true power of Vue CLI: It provides you with a pre-generated template that is based on your specifications. Because of this, it’s already configured so you can start developing your website or application right away. Vue CLI 3 will ask you a few questions via a command line prompt about your project, download the required files, and pre-configure it for you so you are ready to work as soon as it’s done.

      To generate a single-page application, navigate to the directory you’d like your Vue project in, then run the following:

      vue create vue-starter-project
      

      The highlighted section of the command is the name of the root directory of the project. This will be the name of the folder that contains all of your Vue.js project files. This can be whatever you’d like, but in the case of this tutorial, you will use vue-starter-project.

      Once you type out that command, continue by pressing Enter. You will then receive the following prompt:

      Vue CLI v4.5.6
      ? Please pick a preset: 
        Default ([Vue 2] babel, eslint) 
        Default (Vue 3 Preview) ([Vue 3] babel, eslint) 
      ❯ Manually select features 
      

      If you do not want to configure your project and opt for the defaults, you can do so with either Vue 2 or Vue 3. For the purpose of this tutorial though, it’s recommended to manually select your features. By selecting specific features, you will see how each option you selected was installed by the CLI.

      Select Manually select features with ENTER. Immediately you’ll receive a number of different options, including: Choose Vue version, TypeScript, Router, and Vuex. Notice that some of these items are already selected (the bubble is filled in). You may select as many or as few as you’d like. However, for this tutorial, select the following by pressing <space> on the entry:

      ...
       ◉ Choose Vue version
       ◉ Babel
       ◉ TypeScript
       ◯ Progressive Web App (PWA) Support
       ◉ Router
       ◉ Vuex
       ◉ CSS Pre-processors
       ◉ Linter / Formatter
      ❯◯ Unit Testing
       ◯ E2E Testing
      

      Once you have your options selected, press the ENTER key. The CLI will ask you further questions regarding each of the features you selected for your project, in order. The first question will ask which version of Vue you’d like to use: 2.x or 3.x. You’ll use Vue 3 for this tutorial, but you may want to use Vue 2 if you want greater support from the Vue Community:

      ...
      ? Choose a version of Vue.js that you want to start the project with 
        2.x 
      ❯ 3.x (Preview)
      

      The next question is regarding TypeScript integration. If you are not familiar with TypeScript, that’s alright. This option was intentionally selected to illustrate how Vue CLI 3 downloads what you defined as required for unique project. This tutorial will not use the class-style syntax, but will use Babel alongside TypeScript.

      When encountering the following, enter N:

      ...
      Use class-style component syntax? (y/N) N
      

      In the following prompt, enter Y:

      ...
      ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n) Y
      

      Next, Vue CLI will ask about history mode. History mode will make each route its own URL. This means you will not have the /#/ (hash) in your application’s URL. If you do use history mode, you will need a Node server to run your project. This is not a problem, because Vue CLI 3 provides you with a Node server.

      Type Y to answer yes to history mode:

      ...
      ? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) Y
      

      The next question is regarding CSS pre-processors such as Sass or LESS. A CSS pre-processor is CSS with added features like nesting and variables. The browser cannot read this, so when the project is built, Node will compile all of your SCSS or LESS code to traditional CSS. Since you are using Node to build your project, it’s recommended to select Sass/SCSS (with node-sass) as your pre-processor. Later on, you’ll add lang attributes in your .vue components to enable SCSS on a per component basis:

      ...
      ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): 
        Sass/SCSS (with dart-sass) 
      ❯ Sass/SCSS (with node-sass) 
        Less 
        Stylus 
      

      After that, you will receive some questions regarding the linter style. A linter is a program that evaluates your code as you develop your application. This linter can enforce a number of syntactical rules during development. In addition to this, your integrated development environment (IDE) can read this configuration file and format your code on save. This will keep your code consistent no matter who works on your project and what operating system or IDE a developer is using.

      For this tutorial, choose ESLint + Standard config:

      ...
      ? Pick a linter / formatter config: 
        ESLint with error prevention only 
        ESLint + Airbnb config 
      ❯ ESLint + Standard config 
        ESLint + Prettier 
        TSLint (deprecated) 
      

      This selects a set of rules for ESLint to enforce. These configurations include options like the use of trailing commas, semi-colons at the end of a line, or using const over var in JavaScript.

      The next option is selecting when you want ESLint to format your code. This can be either on save or when you commit your code to a service like GitHub, GitLab, or BitBucket. It’s recommended to select Lint on save so you can review any changes before committing to version control:

      ...
      ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
      ❯◉ Lint on save
       ◯ Lint and fix on commit
      

      Once you select your lint features, Vue CLI will ask you about how you want to store these configurations, whether in dedicated files or in the package.json. It’s considered standard practive to store configurations in their own files for a few reasons. One, configurations are easier to share between projects this way, and two, you’ll be keeping your package.json as legible as possible by only defining the important information about your app:

      ...
      ? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
      ❯ In dedicated config files 
        In package.json
      

      Once you are done, the CLI tool will ask if you want to save this selection as a preset for future projects. This is useful if you are generating projects for your employer and you want everything to stay consistent.

      Go ahead and save this configuraion as a preset; Vue CLI will ask you to rename it. Name it DigitalOcean Vue Tutorial Series:

      ...
      ? Save this as a preset for future projects? Yes
      ? Save preset as: DigitalOcean Vue Tutorial Series
      

      Now you can use these exact same settings for a future project.

      At this point, you will have something along the lines of this in your terminal summarizing all of your options:

      ? Please pick a preset: Manually select features
      ? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter
      ? Choose a version of Vue.js that you want to start the project with 3.x (Preview)
      ? Use class-style component syntax? No
      ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
      ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
      ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with node-sass)
      ? Pick a linter / formatter config: Standard
      ? Pick additional lint features: Lint on save
      ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
      ? Save this as a preset for future projects? (y/N) 
      

      Press ENTER, and Vue CLI will start creating your app.

      When completed, cd (change directory) in your project name (vue-starter-project):

      Next, start the application with npm run serve. This will run your project at a port on your localhost, usually :8080. If it’s a different port, the CLI will tell you:

      npm run serve
      

      You do not need to download dependencies, as the CLI already did that for you. To view your generated project, open your browser of choice and visit localhost:8080 in the URL bar. You will find a welcome screen with the Vue logo and the technologies you’ve selected in the previous steps.

      Vue template screen

      You can leave this server running throughout this tutorial to monitor your changes.

      In this section, you selected a number of options specific to the project you are creating. Vue CLI downloaded all of the code needed and pre-configured it for you. You can now start working in the generated code base, including creating your own single-file .vue components.

      Now that you have a single-page application running on a Node server, make some changes to this by creating a standard header and footer. These AppHeader.vue and AppFooter.vue components will be imported in such a way that they’ll be present on each route.

      In a new terminal window, navigate into the root of your vue-starter-project folder and list out the files with the following command:

      You will receive the following output:

      Output

      README.md babel.config.js node_modules package-lock.json package.json public src tsconfig.json

      You can also view the contents of your project by opening your project in your editor of choice, such as Visual Studio Code. In either case, you will have access to a number of different files and directories. These config files in the root directory have been created because of the selections made during the intial generation of this project. The option In dedicated config files told Vue CLI to create config.js files for each service you are using, such as Babel, TypeScript, and ESLint. In addition to these files, there are a number of directories. This tutorial will go over these as you get to them.

      First, create a .vue file in the components directory and name it AppHeader.vue. You can do this right-clicking in the components directory and creating a new file in IDEs like VS Code. If you prefer terminal commands, you can do this in your computer’s terminal with the bash command touch:

      touch src/components/AppHeader.vue
      

      In this step, you are creating a single-file component that will contain all of the HTML, JavaScript, and SCSS that this chunk of code needs. Every .vue component contains three basic concerns or sections: <template>, <script>, and <style>. In this case, template is the component’s HTML.

      Open up the new file in your text editor.

      In this file, create a header by using the <header> tag inside of <template>. Inside of this <header>, add the Vue.js logo and a <p> element with the content My Vue.js Application:

      vue-starter-project/src/components/AppHeader.vue

      <template>
        <header>
          <img alt="Vue logo" src="https://www.digitalocean.com/community/tutorials/assets/logo.png" height="50">
          <p>My Vue.js Application</p>
        </header>
      </template>
      

      Keep your development server running throughout development. If you close or cancel the server process, you will not be able to view your application in the browser.

      Save the file.

      At this point, when you open your browser, you will not see the HTML rendered. That is because you need to import the newly created AppHeader.vue component into a component that is already mounted. Since App.vue is your main entry point, it’s best to import it there so our header appears on every route.

      Open up the App.vue file in your text editor, then delete the div with the ID of nav and add the following highlighted code:

      vue-starter-project/src/App.vue

      <template>
        <app-header />
        <router-view/>
      </template>
      
      <script>
      import AppHeader from '@/components/AppHeader.vue'
      
      export default {
        components: {
          AppHeader
        }
      }
      </script>
      

      When you import using ES6, you are essentially creating a variable to later reference in your code. In this case, you are storing the code from AppHeader.vue into a variable called AppHeader. You need to register it via the components property before you can use it.

      Once it’s imported, you deleted the #nav in the template and added <app-header /> before the <router-view />. This renders the component in the HTML.

      After completing this step, save any unsaved file and open your browser back to localhost:8080. Thanks to hot module reloading, you will now find your newly created header at the top of the page:

      Vue template with new header

      You’ve now created a single-file Vue component, used import to bring it into a mounted component, and monitored the change with hot module reloading (HMR). Moving forward, you will extend the functionality of components through the use of child components. You will also use SCSS (the pre-processor you selected earlier) on a per component basis with the lang attribute.

      Now that the header is imported properly into the application, return to AppHeader.vue in your text editor. Add navigation underneath <p>My Vue.js Application</p> by adding the following highlighted code:

      vue-starter-project/src/components/AppHeader.vue

      <template>
        <header>
          <img alt="Vue logo" src="https://www.digitalocean.com/community/tutorials/assets/logo.png" height="50">
          <p>My Vue.js Application</p>
          <nav>
            <ul>
              <li><router-link to="/">Home</router-link></li>
              <li><router-link to="/about">About</router-link></li>
            </ul>
          </nav>
        </header>
      </template>
      

      Now, style this to make it look more like a traditional navigation bar. Create a <style> tag at the end of the file.

      vue-starter-project/src/components/AppHeader.vue

      <template>
        <header>
          <img alt="Vue logo" src="https://www.digitalocean.com/community/tutorials/assets/logo.png" height="50">
          <p>My Vue.js Application</p>
          <nav>
            <ul>
              <li><router-link to="/">Home</router-link></li>
              <li><router-link to="/about">About</router-link></li>
            </ul>
          </nav>
        </header>
      </template>
      
      <style lang="scss">
      </style>
      

      During the inital setup, you selected the Sass/SCSS (with node-sass) option. This is why you added on the lang="scss" attribute to your style tag. If you are unfamiliar with SCSS, it’s recommended to view their official documentation for specifics on when to use nesting or variables.

      This lang attribute will give you the ability to write SCSS in your single-file component. Add the following highlighted contents in the style element:

      vue-starter-project/src/components/AppHeader.vue

      ...
      <style lang="scss">
        header {
          display: flex;
          border-bottom: 1px solid #ccc;
          padding: .5rem 1rem;
      
          p {
            margin-left: 1rem;
          }
        }
      
        nav {
          margin-left: auto;
      
          ul {
            list-style: none;
          }
      
          ul li {
            display: inline-flex;
            margin-left: 1rem;
          }
        }
      </style>
      

      This SCSS creates a horizontal navigation bar with declarations such as display: inline-flex (using Flexbox) and spaces each item out with margin-left auto. To separate the header from the rest of the content, some padding is applied with padding: .5rem 1rem along with a bottom border using border-bottom: 1px solid #ccc. You may notice that the p styles are inside of the header SCSS block. In traditional CSS, that is not allowed, but thanks for SCSS, you can do that. This is refered to as nesting. In this case, the p inside the header is the same as selecting header p in traditional CSS.

      Save your file and navigate to localhost:8080 in your browser to find the new style:

      New style for header in Vue template

      You now have created and styled your header component. Next, you will create the footer component.

      Now that you have a header, you will complete your example application with a footer. In the same components directory, create a new file with the name AppFooter.vue. The process of creating this component is the same as creating the AppHeader.vue. You can create the file in your editor or through the touch base command.

      touch src/components/AppFooter.vue
      

      As before, import this into your App.vue file. Open up App.vue and add the following highlighted code:

      vue-starter-project/src/App.vue

      <template>
        <app-header />
        <router-view/>
        <app-footer />
      </template>
      
      <script>
      import AppHeader from '@/components/AppHeader.vue'
      import AppFooter from '@/components/AppFooter.vue'
      
      export default {
        components: {
          AppHeader,
          AppFooter
        }
      }
      </script>
      ...
      

      This time, you’re importing the component after the router-view tag.

      Save the file, then open up AppFooter.vue. In your AppFooter.vue file, use the <footer> HTML tag with a paragraph:

      vue-starter-project/src/components/AppFooter.vue

      <template>
        <footer>
          <p>Copyright &copy; "current year" </p>
        </footer>
      </template>
      

      You now have a basic footer. Continue to expand on this to include the current year programmatically. This will be dynamic depending on what the year is. To achieve this, you will create a computed property. A computed property is a reactive value calculated with JavaScript.

      In Vue 3, you need to wrap your properties in the setup() function and return these values. Essentially, you are telling Vue to construct this component and provide the template to these reactive computed properties.

      To create a computed property, you’ll first need to deconstruct the computed function from the vue library. You will store this computed function and its value into a const. In Vue 3, you need to pass an anonymous function that returns a value:

      const year = computed(() => new Date().getFullYear())
      

      To add the setup function to your file, add the following script to the end of AppFooter.vue:

      vue-starter-project/src/components/AppFooter.vue

      ...
      <script>
      import { computed } from 'vue'
      
      export default {
        setup () {
          const year = computed(() => new Date().getFullYear())
        }
      }
      </script>
      

      After that, you will need to provide access to the computed property you created for the <template> to consume and render. Return an object with the year property and value in your setup() function:

      /vue-starter-project/src/components/AppFooter.vue

      ...
      setup () {
        const year = computed(() => new Date().getFullYear())
        return { year }
      }
      ...
      

      To use this value in the <template>, use interpolation with double curly braces. This is sometimes referred to the “moustache syntax”:

      /vue-starter-project/src/components/AppFooter.vue

      <template>
        <footer>
          <p>Copyright &copy; {{ year }}</p>
        </footer>
      </template>
      

      Save the file. You will now have the current year in your footer:

      Sample vue application with a computed header

      Conclusion

      In this tutorial, you downloaded the Vue CLI and created your own single-file components with AppHeader.vue and AppFooter.vue. You successfully generated a Vue.js Single Page Application (SPA) with selected features from the initial setup, and learned how all of those pieces come together. In addition, you’ve now reviewed the basic architecture of most SPAs and can use that knowledge to futher expand this project.

      Vue.js is a growing ecosystem with a number of tools at your disposable. These tools can help you quickly get started and save time by storing options as a preset. This is just the start of what Vue.js has to offer, but the CLI is perhaps one of the most important tools you will use in your Vue.js journey.

      For more information on Vue.js and Vue CLI 3, it’s recommended to read through their documentation. The CLI tool specifically has many additional features that weren’t covered in this tutorial. For more tutorials on Vue, check out the Vue Topic Page.



      Source link

      How to Generate a Short and Unique Digital Address for Any Location Using AngularJS and PHP


      Introduction

      Postal addresses are usually lengthy and sometimes difficult to remember. There are a number of scenarios where a shorter address would be desirable. For example, having the ability to send a short address consisting of only a couple of characters could ensure faster delivery of emergency ambulance services. Pieter Geelen and Harold Goddijn developed the Mapcode system in 2001 to make it easy to create a short-form address for any physical address in the world.

      In this tutorial, you will develop a web app that uses the Google Maps API to generate a short digital address for any address of your choice. You will do this by cloning the base code for this app from GitHub and then adding code to it that will make it fully functional. This app will also be able to retrieve the original physical address from a given mapcode.

      Prerequisites

      In order to complete this tutorial, you will need the following:

      Step 1 — Getting a Google API Key

      In this tutorial, you will use JavaScript to create an interface to Google Maps. Google assigns API keys to enable developers to use the JavaScript API on Google Maps, which you will need to obtain and add to your web app’s code.

      To get your own API key, head to Google’s “Get API Key” page. Click on the GET STARTED button in Step 1, and a pop-up will open as shown in the following image:

      Select Maps by clicking the check box and hit CONTINUE. If you aren’t already logged into a Google account, you will be asked to do so. Then, the window will ask you to provide a name for the project, which can be anything you’d like:

      Following this, it will ask you to enter your billing information. Note that Google provides API keys as part of a free trial, but it requires you to set up and enable billing in order retrieve them.

      After entering this information, your API key will appear on the screen. Copy and store it in a location where you can easily retrieve it, as you will need to add it to your project code later on.

      After obtaining your API key, you can begin building the foundation of your application by creating a MySQL database.

      Step 2 — Creating the Database

      The web application described in this tutorial accepts an address from the user and generates a mapcode for it along with the latitude and longitude of the specified location. You will store this data in a MySQL database so that you can retrieve it later on just by entering the respective digital address.

      Begin by opening the MySQL shell and authenticating with your password:

      At the prompt, create a database called digitaladdress using the following command:

      • CREATE DATABASE IF NOT EXISTS `digitaladdress`;

      Next, select this new database so that you can create a table within it:

      After selecting the digitaladdress database, create a table called locations within it to store the physical address, its longitude, latitude, and the mapcode that your application will create from this data. Run the following CREATE TABLE statement to create the locations table within the database:

      • CREATE TABLE `locations` (
      • `digitaladdress` varchar(50) DEFAULT NULL,
      • `state` varchar(30) DEFAULT NULL,
      • `zip` varchar(30) DEFAULT NULL,
      • `street` varchar(30) DEFAULT NULL,
      • `town` varchar(30) DEFAULT NULL,
      • `house` varchar(30) DEFAULT NULL,
      • `latitude` varchar(30) DEFAULT NULL,
      • `longitude` varchar(30) DEFAULT NULL,
      • KEY `digitaladdress` (`digitaladdress`)
      • );

      This table has eight columns: digitaladdress, state, zip, street, town, house, latitude, and longitude. The first column, digitaladdress, is indexed using the KEY command. Indexes in MySQL function similarly to how they work in an encyclopedia or other reference work. Any time you or your application issue a query containing a WHERE statement, MySQL reads every entry in each column, row-by-row, which can become an extremely resource-intensive process as your table accumulates more and more entries. Indexing a column like this takes the data from the column and stores it alphabetically in a separate location, which means that MySQL will not have to look through every row in the table. It only has to find the data you're looking for in the index and then jump to the corresponding row in the table.

      After adding this table, exit the MySQL prompt:

      With your database and table set up and your Google Maps API key in hand, you're ready to create the project itself.

      Step 3 — Creating the Project

      As mentioned in the introduction, we will clone the base code for this project from GitHub and then add some extra code to make the application functional. The reason for this, rather than walking you through the process of creating each file and adding all the code yourself, is to speed up the process of getting the app running. It will also allow us to focus on adding and understanding the code that allows the app to communicate with both the Google Maps and Mapcode APIs.

      You can find the skeleton code for the full project on this GitHub project page. Use the following git command to clone the project to your server:

      • git clone https://github.com/do-community/digiaddress.git

      This will create a new folder called digiaddress in your home directory. Move this directory to your server's web root. If you followed the LAMP stack tutorial linked in the prerequisites, this will be the /var/www/html directory:

      • sudo mv digiaddress/ /var/www/html/

      This project contains several PHP and JS files to which you'll add some code later on in this tutorial. To view the directory structure, first install the tree package using apt:

      Then run the tree command with the digiaddress directory given as an argument:

      • tree /var/www/html/digiaddress/

      Output

      digiaddress/ ├── README.md ├── db.php ├── fetchaddress.php ├── findaddress.php ├── generateDigitalAddress.php ├── geoimplement.php ├── index.php └── js ├── createDigitialAddressApp.js └── findAddressApp.js

      You can see from this output that the project consists of six PHP files and two JavaScript files. Together, these files create the application's two main functionalities: creating a mapcode from a physical address, and decoding a mapcode to retrieve the original physical address. The following files enable the first functionality:

      • index.php
      • geoimplement.php
      • generateDigitialAddress.php
      • db.php
      • createDigitialAddressApp.js

      The index.php file contains the code for the application's user interface (UI), which consists of a form where users can enter a physical address. The index.php file calls the geoimplement.php file any time a user submits the form. geoimplement.php makes a call to the Google Maps API and passes the address along to it. The Google server then responds with a JSON containing the specified address's information, including its latitude and longitude. This information is then passed to the generateDigitalAddress.php file which calls the Mapcode API to obtain a mapcode for the given location, as specified by its latitude and longitude. The resulting mapcode, along with the latitude, longitude, and the physical address, are then stored in the database that you created in Step 2. db.php acts as a helper for this operation. The createDigitalAddressApp.js file performs a number of operations that control the UX elements seen in the app, including setting a marker and boundary rectangle on the Google Maps interface.

      The remaining three files enable the second function of the application — that is, retrieving a physical address from a given mapcode:

      • findaddress.php
      • fetchaddress.php
      • findAddressApp.js

      The findaddress.php file defines the application UI, which is distinct from the one defined in index.php. The application accepts a previously-generated mapcode as an input and displays the corresponding physical address stored in the database. Whenever a user submits this form, findaddress.php sends a call to fetchaddress.php which then retrieves the respective mapcode from the database. The findAddressApp.js file contains the helper code for setting a marker and a boundary rectangle on the Google Maps interface.

      Test the installation by visiting http://your_server_ip/digiaddress in your browser, making sure to change your_server_ip to reflect your server's IP address.

      Note: If you don't know your server's IP address, you can run the following curl command. This command will print the page content of icanhazip.com, a website that shows the IP address of the machine accessing it:

      • curl http://icanhazip.com

      Once there, you will see this heading at the top of your browser window:

      Generate Digital Address
      

      This confirms that you have correctly downloaded the project files. With that, let us proceed with the development of the app's primary function: generating a mapcode.

      Step 4 — Developing the Application's UI

      While the boilerplate code for the application interface is included in the files you downloaded in the previous step, you still need to make a few changes and additions to some of these files to make the application functional and engaging for users. We will get started with updating the code to develop the application's UI.

      Open the index.php file using your preferred editor. Here, we'll use nano:

      • nano /var/www/html/digiaddress/index.php

      Look for the following line of code:

      /var/www/html/digiaddress/index.php

      . . .
      <script async defer src="https://maps.googleapis.com/maps/api/js?key=<YOUR KEY>"></script>
      . . .
      

      Replace <YOUR KEY> with the Google API key you obtained in Step 1. After adding your API key, the line should look similar to this:

      /var/www/html/digiaddress/index.php

      . . .
      <script async defer src="https://maps.googleapis.com/maps/api/js?key=ExampleAPIKeyH2vITfv1eIHbfka9ym634Esw7u"></script>
      . . .
      

      Next, find the following comment in the index.php file:

      /var/www/html/digiaddress/index.php

      . . .
                  <!-- add form code here -->
      . . .
      

      We'll add a few dozen lines of code below this comment which will create a form where users can enter the address of a physical location which the application will use to generate a mapcode. Under this comment, add the following highlighted code which creates a title called Enter Address at the top of the form:

      /var/www/html/digiaddress/index.php

      . . .
                  <!-- add form code here -->
      
                  <div class="form-border spacing-top">
                      <div class="card-header" style="background:#cc0001; color:#ffff">
                          <h5>Enter Address</h5>
                      </div>
                      <div class="extra-padding">
      . . .
      

      Below this, add the following HTML code. This creates a form with five text fields (along with their appropriate labels) where users will input their information:

      /var/www/html/digiaddress/index.php

                      . . .
                      <form>
                              <div class="form-group input-group-sm">
                                  <label for="state">State</label>
                                  <input type="text" class="form-control rounded-0 textbox-border" id="state"
                                         placeholder="" ng-model="address.state"/>
                              </div>
                              <div class="form-group input-group-sm">
                                  <label for="zip" class="animated-label">Zip</label>
                                  <input type="text" class="form-control rounded-0 textbox-depth textbox-border"
                                         id="zip" ng-model="address.zip" disabled="disabled"/>
                              </div>
                              <div class="form-group input-group-sm">
                                  <label for="town">Town</label>
                                  <input type="text" class="form-control rounded-0 textbox-border"
                                         id="town" ng-model="address.town" disabled="disabled"/>
                              </div>
                              <div class="form-group input-group-sm">
                                  <label for="street">Street</label>
                                  <input type="text" class="form-control rounded-0 textbox-border" id="street"
                                         placeholder="" ng-model="address.street" disabled="disabled"/>
                              </div>
                              <div class="form-group input-group-sm">
                                  <label for="house">House</label>
                                  <input type="text" class="form-control rounded-0 textbox-border" id="house"
                                         placeholder="" ng-model="address.house" disabled="disabled"/>
                              </div>
                       . . .
      

      Below the form code, add the following lines. These create two hidden controls which pass along the latitude and longitude information derived from any address submitted through the form:

      /var/www/html/digiaddress/index.php

                                  . . .
                                  <div class="form-group input-group-sm">
                                      <input type="hidden" ng-model="address.lat"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <input type="hidden" ng-model="address.long"/>
                                  </div>
                                  . . .
      

      Lastly, close out this section by adding the following code. This creates a Generate button which will allow users to submit the form:

      /var/www/html/digiaddress/index.php

                                  . . .
                                  <button type="submit" disabled="disabled" class="btn btn-color btn-block rounded-0" id="generate"
                                          style="color:#ffff;background-color: #cc0001;">Generate
                                  </button>
                          </form>
                      </div>
                  </div>
              . . .
      

      After adding these elements, this section of the file should match this:

      /var/www/html/digiaddress/index.php

      . . .
                  <!-- add form code here -->
      
                  <div class="form-border spacing-top">
                      <div class="card-header" style="background:#cc0001; color:#ffff">
                          <h5>Enter Address</h5>
                      </div>
                      <div class="extra-padding">
                          <form>    
                                  <div class="form-group input-group-sm">
                                      <label for="state">State</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="state"
                                             placeholder="" ng-model="address.state"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="zip" class="animated-label">Zip</label>
                                      <input type="text" class="form-control rounded-0 textbox-depth textbox-border"
                                             id="zip" ng-model="address.zip" disabled="disabled"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="town">Town</label>
                                      <input type="text" class="form-control rounded-0 textbox-border "
                                             id="town" ng-model="address.town" disabled="disabled"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="street">Street</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="street"
                                             placeholder="" ng-model="address.street" disabled="disabled"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="house">House</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="house"
                                             placeholder="" ng-model="address.house" disabled="disabled"/>
                                  </div>
      
                                  <div class="form-group input-group-sm">
                                      <input type="hidden" ng-model="address.lat"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <input type="hidden" ng-model="address.long"/>
                                  </div>
                                  <button type="submit" disabled="disabled" class="btn btn-color btn-block rounded-0" id="generate"
                                          style="color:#ffff;background-color: #cc0001;">Generate
                                  </button>
                          </form>
                      </div>
                  </div>
                  <br>
              </div>
      
              <!-- add google map control -->
                          . . .
      

      Save the file by pressing CTRL+O then ENTER, and then visit the application in your browser again:

      http://your_server_ip/digiaddress
      

      You will see the newly-added form fields and Generate button, and the application should look like this:

      At this point, if you enter address information into the form and try clicking the Generate button, nothing will happen. We will add the mapcode generation functionality later on, but let's first focus on making this page more visually engaging by adding a map which users can interact with.

      Step 5 — Adding Google Maps Controls

      When maps are displayed on a website through the Google Maps JavaScript API, they contain user interface features that allow visitors to interact with the map they see. These features are known as controls. We will continue editing the index.php file to add Google Maps controls to this app and, when finished, users will be able to view a map next to the input form, drag it around to view different locations, zoom in and out, and switch between Google's map, satellite, and street views.

      Find the following comment within the index.php file:

      /var/www/html/digiaddress/index.php

      . . .
      <!-- add google map control -->
      . . .
      

      Add the following highlighted code below this comment:

      /var/www/html/digiaddress/index.php

      . . .
              <!-- add google map control -->
      
              <div class="col-sm-8 map-align" ng-init="initMap()">
                  <div id="map" class="extra-padding" style="height: 100%;
                  margin-bottom: 15px;"></div>
                  <label id="geocoordinates" ng-show="latlng" ng-model="lt"></label><br/>
                  <label id="geoaddress" ng-show="address" ng-model="padd"></label>
                  </div>
              </div>
      . . .
      

      Save the file, then visit the application in your browser again. You will see the following:

      As you can see, we've successfully added a map to the application. You can drag the map around to focus on different locations, zoom in and out, and switch between the map, satellite, and street views. Looking back at the code you just added, notice that we've also added two label controls that will display the geocoordinates and the physical address that were entered on the form:

      /var/www/html/digiaddress/index.php

                  . . .
                  <label id="geocoordinates" ng-show="latlng" ng-model="lt"></label><br/>
                  <label id="geoaddress" ng-show="address" ng-model="padd"></label>
                  . . .
      

      Visit the application again in your browser and enter the name of a state in the first field. When you move your text cursor to the next field, the latitude and longitude labels don't appear, nor does the location shown on the map change to reflect the information you've entered. Let's enable these behaviors.

      Step 6 — Adding Event Listeners

      Adding interactive elements to an application can help to keep its users engaged. We will implement a few interactive behaviors in this application through the use of event listeners.

      An event is any action that takes place on a web page. Events can be something done by a user or by the browser itself. Examples of common events are:

      • Clicking an HTML button
      • Changing the content of an input field
      • Changing the focus from one page element to another

      An event listener is a directive that tells a program to take a certain action when a specific event takes place. In AngularJS, event listeners are defined with directives that generally follow this format:

      ng-event_type=expression
      

      In this step, we will add an event listener that helps to process the information entered by users into a mapcode whenever they submit the form. We will also add a couple more event listeners that will make the application more interactive. Specifically, we'll use these listeners to change the location shown in the application map, place a marker, and draw a rectangle around the location as users enter information into the form. We'll add these event listeners to index.php, so open that file up again if you've closed it:

      • nano /var/www/html/digiaddress/index.php

      Scroll down to the first batch of code we added, and find the block that begins with <form>. It will look like this:

      /var/www/html/digiaddress/index.php

                      . . .
                          <form>
                                  <div class="form-group input-group-sm">
                                      <label for="state">State</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="state"
                                             placeholder="" ng-model="address.state"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="zip" class="animated-label">Zip</label>
                                      <input type="text" class="form-control rounded-0 textbox-depth textbox-border"
                                             id="zip" ng-model="address.zip" disabled="disabled"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="town">Town</label>
                                      <input type="text" class="form-control rounded-0 textbox-border"
                                             id="town" ng-model="address.town" disabled="disabled"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="street">Street</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="street"
                                             placeholder="" ng-model="address.street" disabled="disabled"/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="house">House</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="house"
                                             placeholder="" ng-model="address.house" disabled="disabled"/>
                                  </div>
                          </form>
      . . .
      

      To begin, add the following highlighted event listener to the opening <form> tag. This code tells the app to call the processForm function whenever a user submits information through the form. processForm is defined in the createDigitalAddressApp.js file, and serves as a helper function that sends the information submitted by users to the appropriate files which then process it into a mapcode. We will take a closer look at this function in Step 7:

      /var/www/html/digiaddress/index.php

                      . . .
                          <form ng-submit="processForm()" class="custom-form">
                                  <div class="form-group input-group-sm">
                                      <label for="state">State</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="state"
                                             placeholder="" ng-model="address.state"
                                  </div>
                      . . .
      

      Next, continue editing this block by adding a couple blur event listeners. A blur event occurs when a given page element loses focus. Add the following highlighted lines to the form block's input tags. These lines tell the application to call the geocodeAddress function when a user's focus shifts away from the respective form fields we created in Step 4. Note that you must also delete the slashes and greater-than signs (/>) that close out each input tag. Failing to do so will prevent the app from registering the blur events correctly:

      /var/www/html/digiaddress/index.php

                      . . .
                      <form ng-submit="processForm()" class="custom-form">
                                  <div class="form-group input-group-sm">
                                      <label for="state">State</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="state"
                                             placeholder="" ng-model="address.state"
                                             ng-blur="geocodeAddress(address,'state')" required=""/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="zip" class="animated-label">Zip</label>
                                      <input type="text" class="form-control rounded-0 textbox-depth textbox-border"
                                             id="zip" ng-model="address.zip" disabled="disabled"
                                             ng-blur="geocodeAddress(address,'zip')" required=""/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="town">Town</label>
                                      <input type="text" class="form-control rounded-0 textbox-border"
                                             id="town" ng-model="address.town" disabled="disabled"
                                             ng-blur="geocodeAddress(address,'town')" required=""/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="street">Street</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="street"
                                             placeholder="" ng-model="address.street" disabled="disabled"
                                             ng-blur="geocodeAddress(address,'street')" required=""/>
                                  </div>
                                  <div class="form-group input-group-sm">
                                      <label for="house">House</label>
                                      <input type="text" class="form-control rounded-0 textbox-border" id="house"
                                             placeholder="" ng-model="address.house" disabled="disabled"
                                             ng-blur="geocodeAddress(address,'house')" required=""/>
                                  </div>
      . . .
      

      The first of these new lines — ng-blur="geocodeAddress(address,'state')" required=""/> — translates to "When the user's focus shifts away from the 'state' field, call the geocodeAddress function." The other new lines also call geocodeAddress, albeit when the user's focus shifts away from their respective fields.

      As with the processForm function, geocodeAddress is declared in the createDigitalAddressApp.js file, but there isn't yet any code in that file that defines it. We will complete this function so that it places a marker and draws a rectangle on the application map after these blur events occur to reflect the information entered into the form. We'll also add some code that takes the address information and processes it into a mapcode.

      Save and close the index.php file (press CTRL+X, Y, then ENTER) and then open thecreateDigitalAddressApp.js file:

      • nano /var/www/html/digiaddress/js/createDigitalAddressApp.js

      In this file, find the following line:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

      . . .
      $scope.geocodeAddress = function (address, field) {
      . . .
      

      This line is where we declare the geocodeAddress function. A few lines below this, we declare a variable named fullAddress which constructs a human-readable mailing address from the information entered by a user into the application's form fields. This is done through a series of if statements:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

      . . .
      var fullAddress = "";
      
          if (address ['house']) {
              angular.element(document.getElementById('generate'))[0].disabled = false;
                  fullAddress = address ['house'] + ",";
                      }
          if (address ['town']) {
              angular.element(document.getElementById('street'))[0].disabled = false;
                  fullAddress = fullAddress + address ['town'] + ",";
          }
          if (address ['street']) {
              angular.element(document.getElementById('house'))[0].disabled = false;
                  fullAddress = fullAddress + address ['street'] + ",";
          }
          if (address ['state']) {
              angular.element(document.getElementById('zip'))[0].disabled = false;
                  fullAddress = fullAddress + address ['state'] + " ";
          }
          if (address ['zip']) {
              angular.element(document.getElementById('town'))[0].disabled = false;
                  fullAddress = fullAddress + address ['zip'];
          }
      . . .
      

      Directly after these lines is the following comment:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

      . . .
      // add code for locating the address on Google maps
      . . .
      

      Underneath this comment, add the following line which checks whether fullAddress is any value other than null:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                      . . .
                      if (fullAddress !== "") {
                      . . .
      

      Add the following code below this line. This code submits the information entered into the form to the geoimplement.php file using the HTTP POST method if fullAddress is not null:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                          . . .
                          $http({
                              method: 'POST',
                              url: 'geoimplement.php',
                              data: {address: fullAddress},
                              headers: {'Content-Type': 'application/x-www-form-urlencoded'}
      
                          }).then(function successCallback(results) {
                          . . .
      

      Next, add the following line which checks whether the PHP call was returned successfully:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                              . . .
                              if (results.data !== "false") {
                              . . .
      

      If the PHP call was successfully returned, we'll be able to process the result. Add the following line, which removes any boundary rectangle that may have been previously drawn on the map by calling the removeRectangle function, which is defined at the top of the createDigitalAddressApp.js file:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                                  . . .
                                  removeRectangle();
                                  . . .
      

      Under the removeRectangle(); line, add the following four lines which will create a marker pointing to the new location on the map control:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                                  . . .
                                  new google.maps.Marker({
                                      map: locationMap,
                                      position: results.data.geometry.location
                                  });
                                  . . .
      

      Then add the following code, which obtains the latitude and longitude information from the result and displays it with the two HTML labels we created in the index.php file in Step 5:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                                  . . .
                                  lat = results.data.geometry.location.lat;
                                  lng = results.data.geometry.location.lng;
      
                                  $scope.address.lat = lat;
                                  $scope.address.lng = lng;
      
                                  geoCoordLabel = angular.element(document.querySelector('#geocoordinates'));
                                  geoCoordLabel.html("Geo Coordinate: " + lat + "," + lng);
      
                                  geoAddressLabel = angular.element(document.querySelector('#geoaddress'));
                                  geoAddressLabel.html("Geo Address: " + fullAddress);
      
                                  $scope.latlng = true;
                                  . . .
      

      Lastly, below these lines, add the following content. This code creates a viewport which marks a new boundary rectangle on the map:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                                  . . .
                                  if (results.data.geometry.viewport) {
      
                                      rectangle = new google.maps.Rectangle({
                                          strokeColor: '#FF0000',
                                          strokeOpacity: 0.8,
                                          strokeWeight: 0.5,
                                          fillColor: '#FF0000',
                                          fillOpacity: 0.35,
                                          map: locationMap,
                                          bounds: {
                                              north: results.data.geometry.viewport.northeast.lat,
                                              south: results.data.geometry.viewport.southwest.lat,
                                              east: results.data.geometry.viewport.northeast.lng,
                                              west: results.data.geometry.viewport.southwest.lng
                                          }
                                      });
      
                                      var googleBounds = new google.maps.LatLngBounds(results.data.geometry.viewport.southwest, results.data.geometry.viewport.northeast);
      
                                      locationMap.setCenter(new google.maps.LatLng(lat, lng));
                                      locationMap.fitBounds(googleBounds);
                                  }
                              } else {
                                  errorLabel = angular.element(document.querySelector('#lt'));
                                  errorLabel.html("Place not found.");
                                  $scope.latlng = true;
                                  removeRectangle();
                              }
      
                          }, function errorCallback(results) {
                             console.log(results);
                          });
                      }
                      . . .
      

      After adding this content, this section of the file will look like this:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

                      . . .
                      // add code for locating the address on Google maps
                      if (fullAddress !== "") {
                          $http({
                              method: 'POST',
                              url: 'geoimplement.php',
                              data: {address: fullAddress},
                              headers: {'Content-Type': 'application/x-www-form-urlencoded'}
      
                          }).then(function successCallback(results) {
      
                              if (results.data !== "false") {
                                  removeRectangle();
      
                                  new google.maps.Marker({
                                      map: locationMap,
                                      position: results.data.geometry.location
                                  });
      
                                  lat = results.data.geometry.location.lat;
                                  lng = results.data.geometry.location.lng;
      
                                  $scope.address.lat = lat;
                                  $scope.address.lng = lng;
      
                                  geoCoordLabel = angular.element(document.querySelector('#geocoordinates'));
                                  geoCoordLabel.html("Geo Coordinate: " + lat + "," + lng);
      
                                  geoAddressLabel = angular.element(document.querySelector('#geoaddress'));
                                  geoAddressLabel.html("Geo Address: " + fullAddress);
      
                                  $scope.latlng = true;
      
                                  if (results.data.geometry.viewport) {
      
                                      rectangle = new google.maps.Rectangle({
                                          strokeColor: '#FF0000',
                                          strokeOpacity: 0.8,
                                          strokeWeight: 0.5,
                                          fillColor: '#FF0000',
                                          fillOpacity: 0.35,
                                          map: locationMap,
                                          bounds: {
                                              north: results.data.geometry.viewport.northeast.lat,
                                              south: results.data.geometry.viewport.southwest.lat,
                                              east: results.data.geometry.viewport.northeast.lng,
                                              west: results.data.geometry.viewport.southwest.lng
                                          }
                                      });
      
                                      var googleBounds = new google.maps.LatLngBounds(results.data.geometry.viewport.southwest, results.data.geometry.viewport.northeast);
      
                                      locationMap.setCenter(new google.maps.LatLng(lat, lng));
                                      locationMap.fitBounds(googleBounds);
                                  }
                              } else {
                                  errorLabel = angular.element(document.querySelector('#lt'));
                                  errorLabel.html("Place not found.");
                                  $scope.latlng = true;
                                  removeRectangle();
                              }
      
                          }, function errorCallback(results) {
                             console.log(results);
                          });
                      }
                      . . .
      

      Save the file, but keep it open for now. If you were to visit the application in your browser again, you wouldn't see any new changes to its appearance or behavior. Likewise, if you were to enter an address and click on the Generate button, the application still would not generate or display a mapcode. This is because we must still edit a few files before the mapcode functionality will work. Let's continue to make these changes, and also take a closer look at how these mapcodes are generated.

      Step 7 — Understanding Mapcode Generation

      While still looking at the createDigitalAddressApp.js file, scroll past the section of code that you added in the previous step to find the code that takes the information submitted through the form and process it into a unique mapcode. Whenever a user clicks the Generate button, the code within the index.php file submits the form and calls the processForm function, which is defined here in createDigitalAddressApp.js:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

      . . .
      $scope.processForm = function () {
      . . .
      

      processForm then makes an HTTP POST to the generateDigitalAddress.php file:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

      . . .
      $http({
          method: 'POST',
          url: 'generateDigitalAddress.php',
          data: $scope.address,
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
      }).then(function (response) {
      . . .
      

      The Stichting Mapcode Foundation provides the API that generates mapcodes from physical addresses as a free web service. To understand how this call to the Mapcode web service works, close createDigitalAddressApp.js and open the generateDigitialAddress.php file:

      • nano /var/www/html/digiaddress/generateDigitalAddress.php

      At the top of the file, you'll see the following:

      /var/www/html/digiaddress/generateDigitalAddress.php

      <?php
      include("db.php");
      . . .
      

      The line reading include("db.php"); tells PHP to include all the text, code, and markup from the db.php file within the generateDigitalAddress.php file. db.php holds the login credentials for the MySQL database you created in Step 2, and by including it within generateDigitalAddress.php, we can add any address information submitted through the form to the database.

      Below this include statement are a few more lines that obtain the latitude and longitude information based on the request submitted by createDigitalAddressApp.js:

      /var/www/html/digiaddress/generateDigitalAddress.php

      . . .
      $data = json_decode(file_get_contents("php://input"));
      $lat = $data->lat;
      $long = $data->lng;
      . . .
      

      Look for the following comment in generateDigitalAddress.php file.

      /var/www/html/digiaddress/generateDigitalAddress.php

      . . .
      // call to mapcode web service
      . . .
      

      Add the following line of code below this comment. This code makes a call the Mapcode API, sending lat and long as parameters.

      /var/www/html/digiaddress/generateDigitalAddress.php

      . . .
      // call to mapcode web service
      $digitaldata = file_get_contents("https://api.mapcode.com/mapcode/codes/".$lat.",".$long."?include=territory,alphabet&allowLog=true&client=web");
      . . .
      

      The web service returns the JSON data which was assigned to digitaldata, and the following statement decodes that JSON:

      /var/www/html/digiaddress/generateDigitalAddress.php

      . . .
      $digitalAddress["status"] = json_decode($digitaldata, TRUE)['local']['territory']." ".json_decode($digitaldata, TRUE)['local']['mapcode'];
      . . .
      

      This returns a mapcode for the user-specified location. The following lines then store this information in the database:

      /var/www/html/digiaddress/generateDigitalAddress.php

      . . .
      $obj = new databaseConnection();
      
      $conn = $obj->dbConnect();
      
      $obj->insertLocation($conn, $digitalAddress["status"],$data->state,$data->zip,$data->street,$data->town,$data->house,$lat,$long);
      . . .
      

      Then, the final line echoes the mapcode back to the caller function:

      /var/www/html/digiaddress/generateDigitalAddress.php

      . . .
      echo json_encode($digitalAddress);
      

      Save and close this file, then reopen createDigitalAddressApp.js again:

      • nano /var/www/html/digiaddress/js/createDigitalAddressApp.js

      When a mapcode has been retrieved successfully, the following lines in the createDigitalAddressApp.js file displays it to the user in a dialog box:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

      . . .
      digiAddress = response.data.status;
      . . .
      $('#digitalAddressDialog').modal('show');
      . . .
      

      Although you did add a new line of code to generateDigitalAddress.php, you still won't see any functional changes when you visit and interact with the app in your browser. This is because you've not yet added your Google API key to the geoimplement.php file, which makes the actual call to the Google Maps API.

      Step 8 — Enabling Calls to the Google Maps API

      This application depends on the Google Maps API to translate a physical address into the appropriate latitude and longitude coordinates. These are then passed on to the Mapcode API which uses them to generate a mapcode. Consequently, if the application is unable to communicate with the Google Maps API to generate the location's latitude and longitude, any attempt to generate a mapcode will fail.

      Recall from Step 6 where, after constructing the address data, we passed the result along via an HTTP POST request in the createDigitalAddressApp.js file:

      /var/www/html/digiaddress/js/createDigitalAddressApp.js

      $http({
          method: 'POST',
          url: 'geoimplement.php',
          data: {address: fullAddress},
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
      }).then(function successCallback(results) {
      

      This code block sends the address data entered by a user to the geoimplement.php file which contains the code that calls the Google Maps API. Go ahead and open this file:

      • nano /var/www/html/digiaddress/geoimplement.php

      You'll see that it first decodes the address that was received through the POST request:

      /var/www/html/digiaddress/geoimplement.php

      . . .
      $data=json_decode(file_get_contents("php://input"));
      . . .
      

      It then passes the address field of the input data to a geocode function which returns the geographic information on the address:

      /var/www/html/digiaddress/geoimplement.php

      . . .
      $result = geocode($data->address);
      . . .
      

      The result is then echoed back to the caller:

      /var/www/html/digiaddress/geoimplement.php

      . . .
      echo json_encode($result);
      . . .
      

      The geocode function encodes the address and passes it on to the Google Maps API, along with your application key:

      /var/www/html/digiaddress/geoimplement.php

      . . .
      // url encode the address
      $address = urlencode($address);
      
      // google map geocode api url
      $url = "https://maps.googleapis.com/maps/api/geocode/json?address={$address}&key=<YOUR KEY>";
      . . .
      

      Before scrolling on, go ahead and add your API key to the line under the // google map geocode api url comment:

      /var/www/html/digiaddress/geoimplement.php

      . . .
      // google map geocode api url
      $url = "https://maps.googleapis.com/maps/api/geocode/json?address={$address}&key=ExampleAPIKeyH2vITfv1eIHbfka9ym634Esw7u";
      . . .
      

      After sending the call to the Google Maps API, the response is decoded and its value is returned by the function:

      /var/www/html/digiaddress/geoimplement.php

      . . .
      // get the json response
      $resp_json = file_get_contents($url);
      
      // decode the json
      $resp = json_decode($resp_json, true);
      
      if ($resp['status'] == 'OK') {
          return $resp['results'][0];
      } else {
          return false;
      }
      . . .
      

      Save this file, and visit your application once again. Input US-NY in the state field and then hit TAB to change the input focus to the next field. You will see the following output:

      Notice that the geocoordinates and physical address that you entered in the form appear underneath the map. This makes the application feel much more engaging and interactive.

      Note: When it comes to abbreviations for place names, Mapcode uses the ISO 3166 standard. This means that it may not interpret some commonly-used abbreviations as expected. For example, if you'd like to generate a Mapcode for an address in Louisiana and you enter LA, the map will jump to Los Angeles, California (rather than the state of Louisiana).

      You can avoid confusion with US postal abbreviations by preceding them with US-. In the context of this Louisiana example, you would enter US-LA.

      To learn more about how Mapcode uses this standard, check out the Territories and standard codes reference page.

      Despite this improvement to how the application displays locations on the map, the app still isn't fully functional. The last step you need to take before you can generate a mapcode is to edit the db.php file to allow the application to access your database.

      Step 9 — Adding Database Credentials and Testing Mapcode Generation

      Recall that this application stores every address entered into the form — along with its latitude, longitude, and mapcode — in the database you created in Step 2. This is made possible by the code within the db.php file, which stores your database credentials and allows the application to access the locations table within it.

      As a final step to enable the mapcode generation functionality, open the db.php file for editing:

      • nano /var/www/html/digiaddress/db.php

      Near the top of this file, find the line that begins with $pass. This line submits your MySQL login credentials in order to allow the application to access your database. Replace your_password with your root MySQL user's password:

      /var/www/html/digiaddress/db.php

      . . .
              $username = "root";
              $pass = "your_password";
      . . .
      

      That is the last change you need to make in order to generate a mapcode from a physical address. Save and close the file, then go ahead and refresh the application in your browser once again. Enter in an address of your choice and click the Generate button. The output will look similar to this:

      At this stage, you have completed your application and you can now generate a short digital address for any physical location in the world. Feel free to experiment with different addresses, and note that the address you enter does not necessarily need to be within the United States.

      Your final task is to enable this app's second functionality: retrieving an address from the database using its respective mapcode.

      Step 10 — Retrieving a Physical Address

      Now that you're able to generate a mapcode from a given physical address, your final step is to retrieve the original physical address, as derived from the mapcode. To accomplish this, we will develop a PHP user interface, shown here:

      The code for this UI is available in the findaddress.php file. As the UI defined within this file is fairly similar to the UI we covered earlier in Step 4, we will not look too closely at all the details of how it works. We will, however, go through these three files to explain generally how they function.

      In order to enable the address retrieval functionality, you'll need to add your Google API key to the findaddress.php file, so open it up with your preferred editor:

      • nano /var/www/html/digiaddress/findaddress.php

      Near the bottom of the file, find the line that begins with <script async defer src=. It will look like this:

      /var/www/html/digiaddress/findaddress.php

      <script async defer src="https://maps.googleapis.com/maps/api/js?key=<YOUR KEY>"></script>
      

      Replace <YOUR KEY> with your Google API key as you've done in the previous steps, then save the file. Before closing it, though, let's take a quick look to see how these files work together.

      When a user submits the form it triggers a submit event, and an event listener calls the fetchadd function:

      /var/www/html/digiaddress/findaddress.php

      . . .
      <form ng-submit="fetchadd()" class="custom-form">
      . . .
      

      The fetchadd function sends the digital address to fetchaddress.php with a POST request:

      /var/www/html/digiaddress/js/findAddressApp.js

      . . .
      $http({
          method : 'POST',
          url : 'fetchaddress.php',
          data : {digiaddress: $scope.digiaddress}
      }).then(function(response){
      . . .
      

      If the POST is successful, the function returns a JSON response. The following line parses this response:

      /var/www/html/digiaddress/js/findAddressApp.js

      . . .
      var jsonlatlng = JSON.parse(response.data.latlng);
      . . .
      

      The next lines set the marker on the map:

      /var/www/html/digiaddress/js/findAddressApp.js

      . . .
      marker = new google.maps.Marker({
          position: new google.maps.LatLng(jsonlatlng.latitude, jsonlatlng.longitude),
              map: locationMap
      });
      . . .
      

      And the following prints the geocoordinates and the physical address:

      /var/www/html/digiaddress/js/findAddressApp.js

      . . .
      geoCoordLabel = angular.element(document.querySelector('#geocoordinates'));
      geoCoordLabel.html("Geo Coordinate: "+ jsonlatlng.latitude +","+ jsonlatlng.longitude);
      
      geoAddressLabel = angular.element(document.querySelector('#geoaddress'));
      geoAddressLabel.html("Geo Address: " + jsonlatlng.house +","+ jsonlatlng.town +","+ jsonlatlng.street +","+ jsonlatlng.state + " " + jsonlatlng.zip );
      . . .
      

      Visit this application in your browser by going to the following link:

      http://your_server_ip/digiaddress/findaddress.php
      

      Test it out by entering in the mapcode you obtained earlier. The following figure shows a typical output:

      With that, your application is finished. You can now create a unique mapcode for any location in the world, and then use that mapcode to retrieve the location's physical address.

      Conclusion

      In this tutorial you used the Google Maps API to pin a location and gets its longitude, latitude information. This information is used to generate a unique and short digital address using Mapcode API. There are a number of practical use cases for mapcodes, ranging from emergency services to archaeological surveying. The Stichting Mapcode Foundation lists several such use cases.

      Acknowledgements

      Many thanks to Dinesh Karpe and Sayli Patil for developing the entire project code.



      Source link