I'm working on my very first web app utilizing the Google Places Autocomplete functionality in the frontend and Flask in the backend.
Current situation:
Whenever an address is selected from the autocomplete suggestions, a variable called 'address' is populated in the background containing the API response as JSON. Using a window alert I can confirm that this part works fine.
To-Do/ issue:
The address variable should be sent over to Flask so that I can do use it going forward.
Using AJAX to post the data however it never seems to reach Flask. The output is always None.
My best guess is that the submit button implemented after the Autocomplete stuff somehow overrides the JSON POST data in order to keep only the actual text which is in the form while submitting*.
Does that make sense? If yes, how can I still send the JSON data successfully? Or is the issue somewhere else?
I would appreciate any help.
Here is my code:
home.html
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
{% from "_formhelpers.html" import render_field %}
<div class="container">
<form class="form form-horizontal" action="" method="post" role="form" novalidate>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=key&libraries=places&language=en"></script>
<script type="text/javascript">
google.maps.event.addDomListener(window, 'load', function () {
var autocomplete = new google.maps.places.Autocomplete(document.getElementById('autocomplete'),{
types: ['geocode']
});
// autocomplete.setFields('address_components');
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var place = autocomplete.getPlace();
var address = place.address_components;
window.alert(JSON.stringify(address));
}
)})
$.ajax({
type: "POST",
url: "/",
data: address,
success: function(){},
dataType: "json",
contentType : "application/json"
});
</script>
<input type="text" id="autocomplete" size=50 style="width: 250px" placeholder="Enter your location" name=inputkiez>
<a href=# id=autocomplete><button class='btn btn-default'>Submit</button></a>
</form>
<div class="row">
or check out <a href='/result'> the latest reviews from others </a>
<div>
</div>
{% endblock %}
routes.py
#app.route('/', methods=['GET','POST'])
def search():
if request.method == 'POST':
jsdata = request.get_json()
flash('Data is: {}'.format(jsdata))
return redirect('/review')
return render_template('home.html')
#app.route('/review', methods=['GET', 'POST'])
def review():
reviewform = ReviewForm()
if reviewform.validate_on_submit():
userreview = Reviews(
reviewcriteria1= reviewform.reviewcriteria1.data,
reviewcriteria2= reviewform.reviewcriteria2.data,
reviewcriteria3= reviewform.reviewcriteria3.data,
)
db.session.add(userreview)
db.session.commit()
return redirect('/result')
return render_template('review.html', form=reviewform)
*The text in the form would include the address selected from Autocomplete but without any additional data obviously. I even managed to pass this text to the next page with request.form.to_dict() but this is not good enough for my use case since I also want at least the postal code to be sent over.
This is not the exact answer to my question but I found a way to send over the data to flask without having to bring in JSON/AJAX at all.
The trick is to send the data from the Autoplaces response as a hidden input of the form:
<form method="post" action="">
<input id="userinput" placeholder="Enter a location" type="text" name="name" class="form-control"><br>
<div id="map" style="height: 300px;width: 300px; float: none; margin: 0 auto;"></div><br>
<input type="hidden" name="address" id="address">
<input type="submit" name="submit" value="Submit" class="form-control btn btn-primary">
<div>or check out <a href='/result'> the latest reviews from others </a></div>
</form>
Then in routes.py you can easily get the data like this:
#app.route('/', methods=['GET','POST'])
def search():
if request.method == 'POST':
address = request.form['address']
# do something
This is basically a slightly modified version of the solution posted here (YT video).
Related
<form action="" method="post" class="f-color" id="email-form">
{% csrf_token %}
<label>Name</label>
<input type="text">
<label>From</label>
<input type="email">
<label>Message</label>
<button type="submit">Sent</button>
</form>
<div class="mt-5" id="spin" style="display: none;">
<div class="loader"></div>
</div>
<div id="msg"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$(document).on("submit", "#email-form", function(event){
event.preventDefault();
$('#spin').show();
$.ajax({
url: "{% url 'contact' %}",
type: "POST",
data: $("#email-form").serialize(),
success: function(data){
$("#spin").hide();
if(data.status == "success"){
$("#msg").html("<p class='alert alert-success'>we will get back to you as soon as possible</p>" );
$("#email-form").reset();
}
}
})
})
})
</script>
using this code I can submit the form successfully, but after the form submission the message(msg) not showing, the 'if condition statement' is perfectly working (for the testing I gave the alert, the alert was worked)
another problem is form reset, for this I'm using
$("#email-form").reset();
but the form dose't reset
how can I solve these problems
try
$('#email-form')[0].reset();
https://stackoverflow.com/a/3786702/8640027
I got a solution for the resetting form after the ajax form submission
$("#email-form").trigger("reset");
I want a user to be able to select from an existing list of options. If the option is not within the ones already in the database, though, they need to be able to add a new item, while remaining on the main form, because after having added the new item they need to be able to save the main form
I was using the JQuery library select2, which allows a tags:True option, thanks to which users can add a new item to a list if not present. Nevertheless, Django validates that field and if it finds an item which is not in the database is raises an error. My initial plan was that of capturing the new value in the view and then (saving first the form with commit=False), if it was not in the database, save it. But this is not doable without forcing Django not to validate the field, which I haven't managed to do.
Another option, which I'm currently investigating, is that of adding a modal pop-up containing the sub-form. Of course I'd like to avoid opening the sub-form in another page, which would work but would be quite non-user-friendly.
models.py:
class Venue(models.Model):
venue_name = models.CharField(max_length=30)
class performanceOfCompositionNoDb(models.Model):
venue = models.ForeignKey(Venue, on_delete=models.SET_NULL, null=True, blank=True)
forms.py:
class VenueForm(forms.ModelForm):
class Meta:
model = Venue
fields = ['venue_name']
views.py:
def composition_edit_view(request, id=id):
form_composition = CompositionForm(request.POST or None, instance=obj)
form_venue = VenueForm(request.POST or None)
if request.method == "POST" and form_composition.is_valid():
form_composition.save()
context = {
'form_composition': form_composition,
'form_venue': form_venue
[...]
def venue_add_view(request):
form_venue = VenueForm(request.POST or None)
if form_venue.is_valid():
form_venue.save()
context = {
'form_venue': form_venue,
}
return render(request, "venue-add.html", context)
my template.html:
{% include '../venue-add.html'%}
<form id="compositionForm" action='.' enctype="multipart/form-data" method='POST'>
{{form_composition}}
<p>Add new venue</p>
<input class="button" type='submit' id='save' value='Save' />
</form>
venue-add.html:
<div class="reveal" id="addvenueModal" data-reveal>
<form action='.' enctype="multipart/form-data" method='POST'>
{% csrf_token %}
<div class="grid-container">
<div class="grid-x grid-padding-x">
{{ form_venue }}
</div>
<input class="button" type='submit' value='Save' />
</div>
</form>
</div>
I'm expecting to open the venue-add form when I click on the 'Add new venue' button, which happens. With the modal open and the new text input, I then click the 'submit' button of the modal. At that point I get a 'Validation error - ['ManagementForm data is missing or has been tampered with']'. I have other formsets in the main template, and it all works correctly if I don't add a new venue.
How can I solve this? Also, if there's a way of using the select2 library and add a new venue in a more dynamic way, do let me know! Thanks.
Testing with XHR
Using XHR gives the same ['ManagementForm data is missing or has been tampered with'] error in the response:
<div class="reveal" id="addVenue" data-reveal>
<form id="addVenueForm" action='.' onsubmit="addVenue(this); return false;" enctype="multipart/form-data" method='POST'>
{% csrf_token %}
<div class="grid-container">
<div class="grid-x grid-padding-x">
{{ form_venue }}
</div>
<input class="button" type='submit' value='Save' />
</div>
</form>
<script type="text/javascript"> "use strict";
function addVenue (oFormElement) {
var oReq = new XMLHttpRequest();
var data = new FormData(oFormElement)
oReq.onload = {}
oReq.onreadystatechange = function() {
if (oReq.readyState == XMLHttpRequest.DONE) {
var result = oReq.responseText;}
}
oReq.open("post", oFormElement.action, true);
oReq.send(data);
} </script>
As I said, I do have formsets (working correctly) in the main form from which I'm launching this modal. This modal doesn't contain any formset though, it's a simple one-field form, with its own csrf token.
Edit 2
OK, so upon further investigating I've found that the error springs from
return render(request, "compositions/composition_edit.html", context)
in the view.py. In other words, when I hit 'submit' in the modal, for some reason the 'submit' of the main form kicks in also, thus generating issues. How can I isolate the 'submit' of the modal and get the 'submit' of the main form not to kick in unless explicitly clicked?
I had to change the action of the modal form to the address I mapped in my urls.py (action='/venue-add/') for that form. That solved the issue.
Now, the newly-added items are not displayed in the main form unless I refresh the page, no matter ho many times I destroy/empty/repopulate the select2() dropdown list. I think this has to do with the fact that the data to the venue dropdown list is sent by the view at the loading of the main form, and that the context remains the same no matter what updates to the database have been made after the page loading.
For the above reason I'm investigating using an API on my own application and GET and POST data via an AJAX call, which still gives me issue. I'm opening another question for that though.
I am new to Django. I am trying to create a website with two input textboxes. When the submit button clicked, I need to update the results from django view to the same template without reloading the webpage.
Here is my code so far:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<H1>Welcome to Test</H1>
<div class="input-group" >
Input Text:<br>
<textarea class="form-control" rows="20" cols="70" name="InputText"
placeholder="Enter your Input Text here" form="myForm">
</textarea>
<span class="input-group-addon"><br></span>
Input TextFSM Template:<br>
<textarea class="form-control" rows="20" cols="70" name="InputTemplate"
placeholder="Enter your template here" form="myForm">
</textarea>
<form action="" method="post" id="myForm">
{% csrf_token %}
<input type="submit" value="Submit">
</form>
</div>
<div id="resultid">
<p>Result:</p>
{{result}}
</div>
</body>
</html>
views.py
class HomePageView(TemplateView):
template_name = "index.html"
def get(self, request, **kwargs):
form = ParserForm()
return render(request, self.template_name, {"form": form})
def post(self, request, **kwargs):
form = ParserForm(request.POST)
if form.is_valid():
inputtext = form['InputText'].value()
template = form['InputTemplate'].value()
# Process the data and get the result
print(result)
return render(request, self.template_name, {'result': result})
How to pass the result to index.html from view but the text entered in the textboxes should be persistent.
There is no direct way to update result in django templates or django views without reloading the page. In addition, once page in rendered you need second request to update that page. You could use jquery ajax to do fetch data from server without reloading page.
Ajax is asynchronous javascript extension which is use to send request with out reloading page. This would help you to do exactly that you want.
You could get more help from here
See following example for an instance.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
<body>
<H1>Welcome to Test</H1>
<div class="input-group" >
Input Text:<br>
<textarea class="form-control" rows="20" cols="70" name="InputText"
placeholder="Enter your Input Text here" form="myForm">
</textarea>
<span class="input-group-addon"><br></span>
Input TextFSM Template:<br>
<textarea class="form-control" rows="20" cols="70" name="InputTemplate"
placeholder="Enter your template here" form="myForm">
</textarea>
<form id="my-form" action="" method="post" id="myForm">
{% csrf_token %}
<input type="submit" value="Submit">
</form>
</div>
<div id="resultid">
<p>Result:</p>
{{result}}
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
(function($){
function processForm( e ){
$.ajax({
url: '/url-to-call/', //replace this with url that you want to hit without reloading the page
dataType: 'text',
type: 'post',
contentType: 'application/x-www-form-urlencoded',
data: $(this).serialize(),
success: function( data, textStatus, jQxhr ){
// manipulate stuff or action
},
error: function( jqXhr, textStatus, errorThrown ){
// This is executed when some error occures
}
});
e.preventDefault();
}
$('#my-form').submit( processForm );
})(jQuery);</body>
</html>
I've become very frustrated by a problem I'm having. I have a large form that's hand-written (not using Django's forms), and am simply trying to access the data from the inputs in the views (in that case, some inputs were posting, others weren't).
Leaving the specifics of that form aside for now since there are too many things at play, in my troubleshooting process I wrote the simplest form I could think of, and am now getting no POST data besides the csrf_token.
I have no idea why this would be, since something similar (and much more complex) works fine on several other django projects I'm running. For this example, I tried with action="" as well to no avail. Is there something incredibly obvious I'm missing?
Here's the html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form method="POST" id="theForm" action="/simpleForm/">{% csrf_token %}
<input type="text" id="theText" value="Where am I?" />
<input type="hidden" id="hiddenInput" value="I don't exist" />
<input type="submit" />
</form>
</body>
</html>
Here is a simple view checking for data:
from django.shortcuts import render
def simpleForm(request):
if (request.method == 'POST'):
print('In post')
print(request.POST)
for i in request.POST.keys():
print('key: {0} value: {1}'.format(i, request.POST[i]))
return render(request, 'simpleForm.html')
else:
return render(request, 'simpleForm.html')
You're missing the 'name' attribute of the tags in your HTML form. Without those, Django will not add them to request.POST
<form method="POST" id="theForm" action="/simpleForm/">{% csrf_token %}
<input type="text" id="theText" name="mytext" value="Where am I?" />
<input type="hidden" id="hiddenInput" name="myhidden" value="I don't exist" />
<input type="submit" />
I have a question on how to call a view function from a template HTML button? Like an onclick function?
Here is the template:
<input id="submit" type="button" onclick="xxx" method="post" value="Click" />
And the views.py is:
def request_page(request):
...do something...
return render_to_response("/directory.html", {})
Thank you very much.
Assuming that you want to get a value from the user input in html textbox whenever the user clicks 'Click' button, and then call a python function (mypythonfunction) that you wrote inside mypythoncode.py. Note that "btn" class is defined in a css file.
inside templateHTML.html:
<form action="#" method="get">
<input type="text" value="8" name="mytextbox" size="1"/>
<input type="submit" class="btn" value="Click" name="mybtn">
</form>
inside view.py:
import mypythoncode
def request_page(request):
if(request.GET.get('mybtn')):
mypythoncode.mypythonfunction( int(request.GET.get('mytextbox')) )
return render(request,'myApp/templateHTML.html')
One option is, you can wrap the submit button with a form
Something like this:
<form action="{% url path.to.request_page %}" method="POST">
<input id="submit" type="button" value="Click" />
</form>
(remove the onclick and method)
If you want to load a specific part of the page, without page reload - you can do
<input id="submit" type="button" value="Click" data_url/>
and on a submit listener
$(function(){
$('form').on('submit', function(e){
e.preventDefault();
$.ajax({
url: $(this).attr('action'),
method: $(this).attr('method'),
success: function(data){ $('#target').html(data) }
});
});
});
How about this:
<a class="btn btn-primary" href="{% url 'url-name'%}">Button-Text</a>
The class is including bootstrap styles for primary button.
you can put the input inside a form like this:-
<script>
$(document).ready(function(){
$(document).on('click','#send', function(){
$('#hid').val(data)
document.forms["myForm"].submit();
})
})
</script>
<form id="myForm" action="/request_page url/" method="post">
<input type="hidden" id="hid" name="hid"/>
</form>
<div id="send">Send Data</div>
For deleting all data:
HTML FILE
class="btn btn-primary" href="{% url 'delete_product'%}">Delete
Put the above code in an anchor tag. (the a tag!)
url.py
path('delete_product', views.delete_product, name='delete_product')]
views.py
def delete_product(request):
if request.method == "GET":
dest = Racket.objects.all()
dest.delete()
return render(request, "admin_page.html")
For example, a logout button can be written like this:
<button class="btn btn-primary" onclick="location.href={% url 'logout'%}">Logout</button>
Where logout endpoint:
#urls.py:
url(r'^logout/$', auth_views.logout, {'next_page': '/'}, name='logout'),