1👍
From your question, we can see that your javascript is trying to parse some text as JSON, but failing because it encounters an invalid character, <
.
Your view code has two branches depnding on whether the hidden_checkbox
value is in the submitted form.
If hidden_checkbox
is present, the view returns a response serialised as JSON.
If hidden_checkbox
is not present, the view returns some kml; as kml is an xml dialect this will be something like <kml>...</kml>
.
Your javascript is trying to parse the kml as JSON, and failing because KML is not valid JSON. (You can demonstrate this by typing JSON.parse('<kml></kml>')
into your browser’s javascript console – you’ll get an error.)
I’d suggest that you have separate event handlers in your javascript, and two separate views in your python, to handle the two submit buttons.
So:
- if the first button is pressed, the javascript event handler for that button submits the POST request, the view returns JSON, the javascript parses the JSON and does whatever it is supposed to do.
- if the second button is pressed, the javascript handler for that button submits the POST request, the view returns the kml, the javascript does not try to parse as JSON and the download should happen automatically if your headers are set correctly.
EDIT: Example code.
HTML
<form id="form" method="POST" action="/export-kml/">
{% csrf_token %}
<!-- Form fields here -->
<!-- Handle clicking on this button with javascript -->
<button type="button" value="Load Entities" data-action="/load-entities/">Load</button>
<!-- Let the browser handle clicks on this button -->
<button type="submit" value="Export KML">Export</button>
</form>
Django Views
def globe(request):
"""Handles retrieving items to be displayed on the virtual globe."""
if request.method == 'POST':
form = EntityGlobeForm(request.POST)
#put items on the virtual globe
if form.is_valid():
#you are going to have to make a panel and paginate footprints
#object_list = ChangeDetectCSV.objects.filter(processing_level='RAW') #AND DATE
sensor = form.cleaned_data.get('layer') #it is really sensor
#if sensor is not
object_list = CesiumEntity.objects.filter(sensor = sensor)
jdata= serialize('geojson', object_list,
geometry_field='mpoly',
fields=('name','file_name', 'id', 'dzi_location', 'country_code', 'corner_coords', 'sensor', 'targetName', 'collection_date'))
return HttpResponse(json.dumps({'data': jdata}))
else:
form = EntityGlobeForm
return render_to_response('swsite/sw_nga_globe.html', {'form':form },
context_instance=RequestContext(request))
def export_kml(request):
"""Handles exporting KML file using information from the form."""
if request.method == 'POST':
form = EntityGlobeForm(request.POST)
# Create the HttpResponse object with the appropriate KML.
if form.is_valid():
print 'building kml'
kml = simplekml.Kml()
kml.newpoint(name="Kirstenbosch", coords=[(18.432314,-33.988862)]) # lon, lat, optional height
response = HttpResponse(kml.kml())
response['Content-Disposition'] = 'attachment; filename="botanicalgarden.kml"'
response['Content-Type'] = 'application/kml'
print 'about to return response: ' + str(response)
return response
else:
form = EntityGlobeForm
return render_to_response('swsite/sw_nga_globe.html', {'form':form },
context_instance=RequestContext(request))
javascript
$(document).ready(function () {
$('button[value="Load Entities"]').on('click', function () {
// Submit the form to the url defined in the button's data-action attribute.
console.log('Handling Loading Entities');
var form = $('#form');
$.ajax({
type: form.prop('method'),''
url: $(this).data('action'),
data: form.serialize(),
success: function (data) {
// Do something with the returned data.
console.log(data);
}
});
});
});
Explanation
I’ve changed the form so that its action attribute points to the view that handles the KML export. The ‘Load Entities’ button has been given a
data-action attribute that points to the view that handles returning JSON data (you must change these urls to match your views). The ‘Export KML’
button has had its type changed to submit, so that clicking on it will submit the form to the KML export view without requiring any javascript.
Based on the code in your question, I’ve simplified the globe
view and added an export_kml
view to handle exporting the kml. Now that we are using two
views there is no longer any need for the hidden_checkbox
logic in the view (or in your javascript).
Your javascript needs to handle clicks on the ‘Load Entities’ button; the clickhandler that I’ve written submits the form to globe
view.
Clicks on the ‘Export KML’ button are handled by the browser; this way if the form is successfully submitted the KML attachment will be return and automatically
handled by the browser. Handling attachments in Ajax POST requests is quite tricky, letting the browser handle it is best.