[GIS] Submit form information from a leaflet popup to MySQL table

javascriptleafletMySQLPHPpopup

I have a leaflet map and I want to have the user fill out a form in a leaflet popup and upon clicking the 'submit' button – the information in the form will be inserted into my MySQL database.

As a final goal, I want the user to place a point on the map (via leaflet.draw) and fill out a form, add the form information and the lat/lng to my database (MySQL) and then add the user's point back to the map with all of the information in a popup.

I have a map, database and php file set up, but the data are not being sent to my database. Any suggestions on where i should go from here? I'm wondering if I set up my form wrong? Maybe some syntax? I am able to add a point to the map and have a popup appear with the form info within it but the when I click 'submit' the data does not appear in my database.

Here is my index html file that holds my map

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="description" content="Example" />
    <meta name="keywords" content="Maps, Leaflet API" /
    <meta name="author" content="Db" />
    <meta name="viewport" content="width=device-width; initial-scale=1.0" />

    <!--import favicon -->
    <link rel="shortcut icon" href="" type="image/x-icon">


    <!--import CSS -->
    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
    <link href='http://fonts.googleapis.com/css?family=Ubuntu:400,500,300' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="http://k4r573n.github.io/leaflet-control-osm-geocoder/Control.OSMGeocoder.css"/>
    <link href='http://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v0.0.2/leaflet.fullscreen.css' rel='stylesheet' />
    <link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
    <link rel="stylesheet" href="http://cdn-geoweb.s3.amazonaws.com/esri-leaflet-geocoder/0.0.1-beta.3/esri-leaflet-geocoder.css" />
    <link rel="stylesheet" href="http://github.com/Leaflet/Leaflet/blob/master/dist/leaflet.css" />
    <link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-draw/v0.2.2/leaflet.draw.css' rel='stylesheet' />
    <link href='http://github.com/tinuzz/leaflet-messagebox/blob/master/leaflet-messagebox.css' rel='stylesheet' />


    <link rel="stylesheet" type="text/css" href="css/CSS_PD.css" />

    <!--import JavaScript-->
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
    <script src="http://github.com/Leaflet/Leaflet/blob/master/src/Leaflet.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    <script src="http://k4r573n.github.io/leaflet-control-osm-geocoder/Control.OSMGeocoder.js"></script>
    <script type="text/javascript" src="http://maps.stamen.com/js/tile.stamen.js?v1.3.0"></script>
    <script src='http://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v0.0.2/Leaflet.fullscreen.min.js'></script>
    <script src="http://rawgithub.com/domoritz/leaflet-locatecontrol/gh-pages/src/L.Control.Locate.js" ></script>
    <script src="http://cdn-geoweb.s3.amazonaws.com/esri-leaflet/0.0.1-beta.5/esri-leaflet-core.js" ></script>      
    <script src="http://cdn-geoweb.s3.amazonaws.com/esri-leaflet-geocoder/0.0.1-beta.3/esri-leaflet-geocoder.js" ></script>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.js"></script>
    <script src='https://api.mapbox.com/mapbox.js/plugins/leaflet-draw/v0.2.2/leaflet.draw.js'></script>
    <script src='http://github.com/tinuzz/leaflet-messagebox/blob/master/leaflet-messagebox.js'></script>

    <!-- connect your html file to an external JavaScript -->
    <script type="text/javascript" src="js/JS_PD_user.js"></script>
    <script type="text/javascript" src="js/Cities.js"></script>



<style>
    body {
        padding: 0;
        margin: 0;
    }
    html, body{
        height: 100%;
        width: 100%;


    }

     #myMap {
    margin-top:50px;
    width:100%;
    height:100%;
  }
</style

    <title>Map</title>
</head>


<body>


    <div class="row">
        <nav class="navbar navbar-default navbar-fixed-top" role="navigation">

            <a class="navbar-brand" href=""><strong>Map</strong></a>

            <div class="nav-collapse">
            <ul class="nav navbar-nav pull-right">



                <li class="" <li/> <a href="about.html" id="aReset">About the map</a></li>

                <li><a href="logout.php">Log Out</a></li>


            </div>
        </nav>
    </div><!-- Row 2 -->

            <div id="myMap">

                </div>


</div>
</body>

Here is my JavaScript file:

var map;
var centerlatlng = L.latLng(35.85199,-119.6577);

var southWest = L.latLng(3.3,-154.2),
northEast = L.latLng(61.5,-58.4),
bounds = L.latLngBounds(southWest, northEast);

var myIcon1 = L.icon({
iconUrl: 'http://www.broomfield.org/images/pages         /N315/blue%20heading%20icons_building.png',
iconSize: [30, 30]
});

var red = L.icon({
iconUrl: 'img/red.png',
iconSize: [30, 30]
});

$(document).ready(function (){

// Creating a tile layer using ESRI - World Physical Map
var aLayerOne = L.tileLayer('http://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png', {
                maxZoom: 19

            });

// Creating a tile layer using MapBox
var aLayerTwo = L.tileLayer('http://api.tiles.mapbox.com/v4/davidjbailey.jg612ji1/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGF2aWRqYmFpbGV5IiwiYSI6InFxSzA5bjgifQ.tDw01mG43kf6hWUIAtBEAw#4/33.75/-117.87', {
                attribution: 'Developed by <a href="http://davidbaileydata.com/">David Bailey</a>',
                maxZoom: 18
            });

// Creating a geojson layer using geojson file
// You can set the style using Leaflet Path Class - http://leafletjs.com/reference.html#path


// Cities
var aLayerThree = L.geoJson(aGeoJson,   {
                    pointToLayer: function (feature, latlng) {
                        return L.marker(latlng,{icon: myIcon1});
                    }, // end of point to layer{

                    onEachFeature: function(feature, layer){

                        layer.on('load', function(e){
                            marker.openPopup();
                        }); //  event functio                    

                        layer.on('click', function(e){
                            map.setView([e.latlng.lat, e.latlng.lng], 11);
                            map.removeLayer(aLayerThree)
                            aDiv.innerHTML = "<center>" + "<strong>Welcome to </strong>" + "<strong>" + feature.properties.name + "!" + "</strong>" + "<br>" + "<h5>" + "Explore the data by zooming in" + "<br>" +
                            "and out and by clicking on points." + "</h5>" + "------------"  + "<h5>" + "Add an incident to the map by clicking on the" +
                            "<br>" + "marker symbol in the upper left corner of the map." + "</h5>" + "</center>"
                        }); //  event function

                        layer.on('mouseover', function(e){                          
                            aDiv.innerHTML = "<strong>" + feature.properties.name + "</strong>"

                            }); // End of mouseover event function
                        layer.on('mouseout', function(e){                           
                            aDiv.innerHTML = "<strong>Click on your city!</strong>"   


                    });   


                }});

//Create our Map Object
map = L.map('myMap', {
            center: centerlatlng,
            zoom:   6,
            maxBounds: bounds,
            minZoom: 4,
            maxZoom: 18,

            layers: [aLayerThree, aLayerTwo]
        });


UserMarker = L.featureGroup().addTo(map);
map.addLayer(UserMarker);

L.drawLocal.draw.toolbar.buttons.marker = 'Add an incident to the map!';


var drawControl = new L.Control.Draw({
draw: {
polygon: false,
polyline: false,
rectangle: false,
marker:{
                icon: red 
            },
circle: false,
},

edit: {
featureGroup: UserMarker
}
});
map.addControl(drawControl);

map.on('draw:created', function (e) {
 var type = e.layerType,
    layer = e.layer;
    var coords = e.layer._latlng;
      console.log(coords);
 UserMarker.addLayer(layer);
 var popup = L.popup({maxWidth: 1000})
    .setLatLng(layer.getLatLng())
    .setContent('<form role="form" id="form" onsubmit="addMarker()">'+

             '<div class="form-group">'+
              '<label class="control-label col-sm-12"><strong>Was the officer following protocol? </strong></label>'+ "<br>" +
              '<select class="form-control" placeholder="Required" id="protocol" name="text">'+
                '<option value="Following Protocol">Following Protocol</option>'+
                '<option value="Not Following Protocol">Not Following Protocol</option>'+
                '<option value="I Dont Know">I Dont Know</option>'+
              '</select>'+ 
          '</div>'+

              '<div class="form-group">'+
               '<label class="control-label col-lg-10"><strong>Jurisdiction </strong></label>'+ "<br>" +
               '<select class="form-control" id="jurisdiction" name="text">'+
                '<option value="City PD">City PD</option>'+
                '<option value="County Sheriff">County Sheriff</option>'+
                '<option value="CHP">CHP</option>'+
                '<option value="Other">Other</option>'+
              '</select>'+ 
          '</div>'+

               '<div class="form-group">'+
              '<label class="control-label col-sm-10"><strong>Was there an arrest? </strong></label>'+ "<br>" +
              '<select class="form-control" id="arrest" name="text">'+
                '<option value="Yes">Yes</option>'+
                '<option value="No">No</option>'+
                '<option value="I Dont Know">I Dont Know</option>'+
              '</select>'+ 
          '</div>'+      

          '<div class="form-group">'+
              '<label class="control-label col-sm-10"><strong>Date </strong> (Example: 8/1/2015) </label>'+ "<br>" +
              '<input type="date" placeholder="Example: 8/1/2015" id="date" name="date" class="form-control"/>'+ 
          '</div>'+

            '<div class="form-group">'+
              '<label class="control-label col-sm-10"><strong>Time Of Day </strong></label>'+ "<br>" +
              '<select class="form-control" id="time" name="text">'+
                '<option value="Morning">Morning</option>'+
                '<option value="Afternoon">Afternoon</option>'+
                '<option value="Night">Night</option>'+
                '<option value="Late Night or Early Morning">Late Night or Early Morning</option>'+
              '</select>'+ 
          '</div>'+

          '<div class="form-group">'+
              '<label class="control-label col-sm-10"><strong>Comments </strong></label>'+ "<br>" +
              '<input type="text" placeholder="Briefly tell us what happened" id="comments" name="comments" class="form-control"/>'+ 
          '</div>'+

          '<div class="form-group">'+
              '<label class="control-label col-sm-10"><strong>Video Link </strong></label>'+ "<br>" +
              '<input type="text" placeholder="Do you have a video? Add link here" id="video" name="video" class="form-control"/>'+ 
          '</div>'+

                        '<div class="form-group">'+
                '<div style="text-align:center;" class="col-xs-11"><button style="text-align:center;" id="submit" value="submit" class="btn btn-primary trigger-submit">Submit</button></div>'+
          '</div>'+ "<br>" +

        '<strong>' + '-' + '</strong'+

          '</form>')
    .openOn(map);
}

)


// add a map event



//Adding a Scale Control
L.control.scale().addTo(map);


    //adding a Layer Control
var baseLayers = {
    "Satellite imagery": aLayerOne,
    "Streets": aLayerTwo
};

// create a variable holding the overlays
var overLays  = {
'Cities': aLayerThree,


}; 

L.control.layers(baseLayers, overLays, {collapsed: false}).addTo(map);

    $(document).ready(function() {
    $.ajaxSetup({cache:false});
    $('#myMap').css('height', ($(window).height() - 50));
    getUsers();
  });

  $(window).resize(function () {
    $('#myMap').css('height', ($(window).height() - 50));
  }).resize();

    ///Creating custom control here
// part 1/3 : Creates a control with the given position
var aControl = L.control({position: 'bottomright'});

// part 2/3 : Should contain code that creates all the neccessary DOM elements for the control
aControl.onAdd = function () {

        aDiv = L.DomUtil.create('div', 'aCustomC'); // create a div with a class "aCustomC"
        aDiv.innerHTML = "<strong>Click on your city!</strong>" // Each HTML element has an innerHTML property that defines both the HTML code and the text that occurs between that element's opening and closing tag.

                    return aDiv;
}; // end function onAdd

// part 3/3 : Add the control to the map
aControl.addTo(map);



    // create the geocoding control and add it to the map
  var searchControl = new L.esri.Controls.Geosearch({useMapBounds: 8}).addTo(map);

  // create an empty layer group to store the results and add it to the map
  var results = new L.LayerGroup().addTo(map);

  // listen for the results event and add every result to the map
  searchControl.on("results", function(data){
  results.clearLayers();
  for (var i = data.results.length - 1; i >= 0; i--) {
  results.addLayer(L.marker(data.results[i].latlng));


};
    });

});// end document ready 

Here is my php file (submit.php) that I use to send my the form information to my database:

<?php
$username = 'name'; 
$password = 'password'; 
$host = 'localhost'; 
$dbname = 'database';



try {
$dbh = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO table (


        protocol,
        jurisdiction,
        arrest,
        date,
        time,
        comments,
        video,
        color


            )
        VALUES (


        '".$_POST["protocol"]."',
        '".$_POST["jurisdiction"]."',
        '".$_POST["arrest"]."',
        '".$_POST["date"]."',
        '".$_POST["time"]."',
        '".$_POST["comments"]."',
        '".$_POST["video"]."',
        '".$_POST["color"]."'

        )

        ";


$dbh->execute($sql);
header("Location: map.php"); /// map.php is the initial map
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}

$dbh = null;

?>

I am now able to add my data to the mysql perfectly, however I am unable to redirect to another page after success. See my ajax request below:

     //do your own request an handle the results
        $.ajax({
                url: 'submit.php',
                type: 'post',
                dataType: 'json',
                data: $("#form").serialize(),
                success: function(data) {
                    location.href = 'Map_member1.php';
            }

         });

Am I using wrong syntax here? I've seen some redirects coded as "window.location.href", "location" and a host of others. Which one should I use? As of now, I click on the 'submit' button but it doesn't do anything and it actually just stays on the popup (the data is being transferred to my database however).

Best Answer

Several things seem to be wrong in your code.

  1. When you have forms inside a Leaflet popup, you want to avoid form submission in the classic way. You typically need to submit using some AJAX behind the scenes that prevent reloading your page. In order to do this, you need to prevent the default behavior for form submission. This question discusses how to achieve this. In your case, it should be sufficient to add some code like:

    $('#form').submit(function(e){
        e.preventDefault();
    });
    

    after the popup creation with the form, after your code

    var popup = L.popup({maxWidth: 1000})
    ...
    SKIPPED, INCLUDING YOUR FORM
    ...
    .openOn(map);
    

    This makes sure your form is not going to be submitted.

  2. You need to write the code for submitting the form manually. You can add this code after the e.preventDefault(); line in the code above or define your function addMarker handling the form submission. Write this function in the global scope, e.g. before your $(document).ready(function (){

    The form submission can be handled e.g. using jQuery's post or ajax function. This answer shows well how to do this part. The URL (action URL) would be your PHP script.

  3. You need to handle the PHP part, i.e. accessing the submitted values and inserting them in the database. The name attribute of your form controls must match the $_POST keys in your PHP file. I think you did assume that the id attribute is defining the $_POST keys. Very often, this means the name attribute has the same value as the id attribute.

    For instance, your line

    <select class="form-control" id="arrest" name="text">
    

    should be

    <select class="form-control" id="arrest" name="arrest">
    

    in order to be able to retrieve its value in PHP using

    $_POST['arrest']
    

    In case your code should not only be for developing purpose, please be aware of SQL injection issues and fix your code before production. Check out e.g. this and this to start.

  4. You would need to do the necessary action in the Leaflet popup manually, such as closing it, or displaying the submitted values. You would do this typically in the success function you provide in the jQuery ajax or post function when submitting the form.