Autocomplete Address Form using Google Map API

Google map is one of the most widely used API of Google as most of the websites use Google map for showing address location. For a static address it’s pretty simple. All you need to do is mention the address and the map will show the nearest location. Problem arrives when the address is dynamically putted by the user. Suppose for an event in event organizer server, one enters the location. The main component used while taking input location is Google Autocomplete. But we went a step further and parsed the entire address based on city, state, country, etc. and allowed user to input the details as well which gave them the nearest location marked in Map if autocomplete couldn’t find the address.

Autocomplete Location

Screenshot from 2016-07-27 06:52:37

As we can see, in the above input box we get suggestions by Google Map on entering first few letters of our address. To this, we need the API https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap. You can find an example code of how to do this here.

After this is done, what we wanted is not to just include this address, but to provide a form to fill up the entire address in case some parts were missing on this address. The function that the autocomplete listens to is “place_changed” . So once we click on one of the options, this event is triggered. Once the event is triggered, we use the autocomplete.getPlace() to get the complete address json. The json looks something like this:

Screenshot from 2016-07-27 07:04:49

Now what we do is we create a form with input fields having the id same as the ones we require(e.g., country, administrative_area_level_1, locality, etc.). After that we select the long_name or the short_name from this json and put the value in the corresponding input field with the ids. The code for the process after getting the json is elaborated here.

Editing Address Form

After doing this it looks something like this:
Screenshot from 2016-07-27 07:12:13

However, now the important part is to show the map according to this fields. Also, every time we update a field, the map should be updated. For this we use a hack. Instead of removing the initial location field completely, we hide the field but keep the binding to autocomplete intact. As a result the map is shown when we select a particular address.

Now when we update the fields in the address form, we append the value of this field to the value in the initial location field. Though the field is hidden but it is still bound to autocomplete. As a result as soon as we append something to the string contained in the field, the map gets updated. Also, the updated value gets stored to the DB. Thus, with every update in field, the pointer is moved to the nearest location formed by appending all the data from the form.

After saving the location data to DB, if we wish to edit it, we can get back the json by making the same request with the location value. And then we will get back the same address form and the map accordingly.

Finally it looks something like this:

Screenshot from 2016-07-27 07:19:56

Adding Notifications, Volunteer Shifts and DB Export in Engelsystem

Admin can change the display message in registration form

The present system doesn’t allow to change the display message in register form. When the system is used for different events it would be useful if the admin is able to change the display message in registration form . I have added feature were admin can change the display message

settings page

By changing the message in the message box admin can change the display message.Now the message looks like this.

register page

Implementation of changing display message.

Adding display_msg field to User Table so that the display_msg can be accessed through the database any where through the code and can be changed easily

ALTER TABLE `User` 
   ADD `display_msg` varchar(255) DEFAULT "By completing this form you're registering as a Chaos-Angel. This script will create you an account in the angel task scheduler.";

Next step is to update the field whenever it is changed by admin

sql_query("UPDATE `User` SET `display_msg`='" . sql_escape($display_message) . "' WHERE  `UID`='" . sql_escape($user['UID']) . "'");

Copy/ Duplicate function for creating new shifts from existing shifts

The present system doesn’t allow admin to edit an existing shift and create a new shift from the existing data of already created shifts . I have created a copy shift option where admin can edit the shift and create a new shift

create new shifts

In this page admin can create new shift or update the existing shift . Admin can change the date , time , no of angels etc as admin used to create shifts.

Implementation of copy shifts function

Once the admin selects create new shifts button , we need to use the same data so we need to store the values in variables. once admin selects the option we need to do all the error handling and create new shifts .

    if (isset($_REQUEST['shifttype_id'])) {
      $shifttype = ShiftType($_REQUEST['shifttype_id']);
      if ($shifttype === false)
        engelsystem_error('Unable to load shift type.');
      if ($shifttype == null) {
        $ok = false;
        error(_('Please select a shift type.'));
      } else
        $shifttype_id = $_REQUEST['shifttype_id'];
    } else {
      $ok = false;
      error(_('Please select a shift type.'));
    }
    
    $title = strip_request_item('title');
    // check for errors
    if (isset($_REQUEST['rid']) && preg_match("/^[0-9]+$/", 
    $_REQUEST['rid']) && isset($room_array[$_REQUEST['rid']]))
      $rid = $_REQUEST['rid'];
    else {
      $ok = false;
      $rid = $rooms[0]['RID'];
      error(_('Please select a location.'));
    }
    
    if (isset($_REQUEST['start']) && $tmp = 
    DateTime::createFromFormat("Y-m-d", trim($_REQUEST['start'])))
      $start = $tmp->getTimestamp();
    else {
      $ok = false;
      error(_('Please select a start date.'));
    }
    
    if (isset($_REQUEST['end']) && 
    $tmp = DateTime::createFromFormat("Y-m-d", trim($_REQUEST['end'])))
      $end = $tmp->getTimestamp();
    else {
      $ok = false;
      error(_('Please select an end date.'));
    }

    if (isset($_REQUEST['start_time']) &&
  $tmp = DateTime::createFromFormat("H:i", trim($_REQUEST['start_time'])))
      $start_time = $tmp->getTimestamp();
    else {
      $ok = false;
      error(_('Please select an start time.'));
    }

    if (isset($_REQUEST['end_time']) && 
    $tmp = DateTime::createFromFormat("H:i", trim($_REQUEST['end_time'])))
      $end_time = $tmp->getTimestamp();
    else {
      $ok = false;
      error(_('Please select an end time.'));
    }
    
    if (strtotime($_REQUEST['start']) > strtotime($_REQUEST['end'])) {
      $ok = false;
      error(_('The shifts end has to be after its start.'));
    }
    if (strtotime($_REQUEST['start']) == strtotime($_REQUEST['end'])) {
      if (strtotime($_REQUEST['start_time']) > 
                                     strtotime($_REQUEST['end_time'])) {
        $ok = false;
        error(_('The shifts end time  has to be after its start time.'));
      }
    }
    if (strtotime($_REQUEST['start']) == strtotime($_REQUEST['end'])) {
      if (strtotime($_REQUEST['start_time']) == 
                                 strtotime($_REQUEST['end_time'])) {
        $ok = false;
        error(_('The shifts start and end at same time.'));
      }
    }
    $angelmode = 'manually';
    foreach ($types as $type) {
      if (isset($_REQUEST['type_' . $type['id']]) && 
      preg_match("/^[0-9]+$/", trim($_REQUEST['type_' . $type['id']]))) {
        $needed_angel_types[$type['id']] = 
                       trim($_REQUEST['type_' . $type['id']]);
      } else {
        $ok = false;
        error(sprintf(_('Please check the needed angels for team %s.'), 
                                              $type['name']));
      }
    }
    if (array_sum($needed_angel_types) == 0) {
      $ok = false;
      error(_('There are 0 angels needed. 
                         Please enter the amounts of needed angels.'));
    }
    if (isset($_REQUEST['back']))
      $ok = false;

    if ($ok) {
      $shifts = array();
      $start = DateTime::createFromFormat("Y-m-d H:i",
                    date("Y-m-d", $start) . date("H:i", $start_time));
      $start = $start->getTimestamp();
      $end = DateTime::createFromFormat("Y-m-d H:i", 
                        date("Y-m-d", $end) . date("H:i", $end_time));
      $end = $end->getTimestamp();  
      $shifts[] = array(
          'start' => $start,
          'end' => $end,
          'RID' => $rid,
          'title' => $title,
          'shifttype_id' => $shifttype_id   
        );
      $shifts_table = array();
      foreach ($shifts as $shift) {
      $shifts_table_entry = [
          'timeslot' => '<span class="glyphicon glyphicon-time"></span> ' . 
date("Y-m-d H:i", $shift['start']) . ' - ' . date("H:i", $shift['end']) . 
'<br />' . Room_name_render(Room($shift['RID'])),
          'title' => ShiftType_name_render(ShiftType($shifttype_id)) . 
           ($shift['title'] ? '<br />' . $shift['title'] : ''),
            'needed_angels' => '' 
        ];
        foreach ($types as $type)
          if (isset($needed_angel_types[$type['id']]) 
          && $needed_angel_types[$type['id']] > 0)
            $shifts_table_entry['needed_angels'] .= '<b>' . 
AngelType_name_render($type) . ':</b> ' . $needed_angel_types[$type['id']]. '<br />';
        
        $shifts_table[] = $shifts_table_entry;
      }

Display shifts in map view .

Map view makes the user/admin easy to view the shifts and easy to sign-up for shifts.Initially was not able to view the shifts but now the shifts can be viewed in both map view and normal view

shifts view

Implementation of map view .

Map view is very nice way of representing events with dates on Y – axis and rooms on X-axis. We need to make blocks and map the key

$_SESSION['user_shifts'][$key] = array_map('get_ids_from_array', $$key);

Here we map the ids and keys and then we need to print the keys against the id’s

Exporting database of user

In a system like this . It would be better if we could get all the user data who want to volunteer so that they can be contacted for other events also.

export database

Here is the code which can be useful for exporting database of any mysql database

function export_xls(){
// filename
$xls_filename = 'export_'.date('Y-m-d').'.xls'; // Define Excel (.xls) file name
// selecting the table user
$sql = "SELECT * FROM `User`";
//enter your mysql root password here
$Connect = @mysql_connect("localhost", "root", "") or die("Failed to connect to MySQL.You need to enter the password:<br />" . mysql_error() . "<br />" . mysql_errno());
// Select database
$Db = @mysql_select_db($databasename, $Connect) or die("Failed to select database:<br />" . mysql_error(). "<br />" . mysql_errno());
// Execute query
$result = @mysql_query($sql,$Connect) or die("Failed to execute query:<br />" . mysql_error(). "<br />" . mysql_errno());

// Header info settings
header("Content-Type: application/xls");
header("Content-Disposition: attachment; filename=$xls_filename");
header("Pragma: no-cache");
header("Expires: 0");
 
// Define separator (defines columns in excel &amp; tabs in word)
$separator = "\t";
 
// Start of printing column names as names of MySQL fields
for ($i = 0 ; $i < mysql_num_fields($result) ; $i++) {
  echo mysql_field_name($result, $i) . "\t";
}
print("\n");
 
// Start while loop to get data
while($row = mysql_fetch_row($result))
{
  $schema= "";
  for( $j=0 ; $j < mysql_num_fields($result) ; $j++)
  {
    
    if(!isset($row[$j])) {
      $schema .= "NULL".$separator;
    }
    elseif ($row[$j] != "") {
      $schema .= "$row[$j]".$separator;
    }
    else {
      $schema .= "".$separator;
    }
  }
  $schema = str_replace($seperator."$", "", $schema);
  $schema = preg_replace("/\r\n|\n\r|\n|\r/", " ", $schema);
  $schema.= "\t";
  print(trim($schema));
  print "\n";
}
}

Coding standards

Coding standards are a set of guidelines, best practices, programming styles and conventions that developers adhere to when writing source code for a project. All big software companies have them.

For our system we use drupal coding standards.

Development: https://github.com/fossasia/engelsystem

Issues/Bugs:Issues