[GIS] Return value from Django view to JS function

geodjangojavascriptpython

I am building a webmap using GeoDjango, Leaflet and PostGIS. I am trying to write a function that returns a raster value from a database when the user clicks on the map (i.e., via a JS alert, or other means). I have read a number of posts on SE but can't seem to get the code to work myself.

The relevant code is below… first, the JS functions:

map.on('click', function(e) {
    var lng = e.latlng.lng;
    var lat = e.latlng.lat;
    console.log("I clicked!");
    resp = updateLatLng(lat, lng);
    console.log('The response is: ', resp);
});

function updateLatLng(lat, lng) {
    var data = {'lat': lat, 'lng': lng, csrfmiddlewaretoken: '{{ csrf_token }}'};
    $.post('{% url 'legend' %}', data);
    var response = '{{result}}';
    return response
};

The legend view in views.py is as follows:

def legend_view(request):

  lat = request.POST['lat']
  lon = request.POST['lng']

  query = "SELECT ST_Value(raster, ST_TRANSFORM(ST_SetSRID(ST_MakePoint(%s, %s), 4326), 4326)) FROM my_raster_layer;" % (lon, lat)

  conn = psycopg2.connect("dbname='mydb' user='postgres'")
  cur = conn.cursor()
  cur.execute(query)
  result = cur.fetchall()[0][0]

  print("\n\n++++++++++++\nInside the legend view\n")
  print("Lat: ", lat, "   Lon: ", lon)
  print("Value: ", result)
  print("++++++++++++\n\n")

  return HttpResponse(result)

When I click on the map, it successfully sends the lat and long values to views.py, as well as successfully queries the database. I can see this because it prints in the terminal I'm running the webmap from. However, it does not seem to be returning the value to the JS, as result is printing nothing.

Some other relevant SE items that I've followed, but can't get to work for my particular case:

  1. https://stackoverflow.com/questions/1445989/passing-python-data-to-javascript-via-django
  2. https://stackoverflow.com/questions/298772/django-template-variables-and-javascript?noredirect=1&lq=1

Best Answer

I haven't used Django, but to my eyes it looks like your problem is with the concept of an AJAX call.

Using jQuery's $.post is an asycnhronous operation, so you can't work with it using a synchonous programming style (i.e. assigning the function's ouput to a variable).

Instead, you must supply a callback function which is exectued after the client recieves the server's response. Depending on how you want to display the data, you have a few different options.

Option 1

The best way, if you don't need to use the value for other operations in JavaScript, is to drop the value into your HTML with jQuery.

Option 2

If you want to use alert you can, but it's bad UX and I wouldn't reccommend it.

Option 3

Finally, if you need to actually work with the variable you can initialize a variable on page load, then assign the new value to that variable in the callback. This is probably more complicated than you need.

Option 4

The NEW best option (because I was bored) is probably to just use the Leaflet popup.

With some help from the jQuery docs:

// Initialize variable for use later
var theValue;
var popup = L.popup();

function updateLatLng(lat, lng) {
    var data = {'lat': lat, 'lng': lng, csrfmiddlewaretoken: '{{ csrf_token }}'};
    $.post('{% url 'legend' %}', data, function(resp) {
        // Option 1
        $("#raster-value").html("The value is: " + resp.result.value);            
        // Option 2
        alert("The value is: " + resp.result.value);
        // Option 3  -  Display the same way as Option 1, but you can
        //              do other stuff with it too.
        theValue = resp.result.value;
        $("#raster-value").html("The value is: " + theValue);
        // Option 4
        popup
          .setLatLng([lat, lng])
          .setContent('<pThe value is:<br />' + resp.result.value + '</p>')
          .openOn(map); // Obviously this assumes the map is initialized
    });
};

I would also suggest that you take a look at this SE post on returning AJAX responses from Django using JSON.

Hope this helps!

Related Question