How to pass a javascript variable to WTForm? Python/Flask - javascript

I am creating a data entry/timing web app using Python and Flask. When the user goes to the log page, they enter in the "session ID" for their task, and the time of form submission and user ID are automatically input to the database as well.
Now I am trying to use Javascript to record when the page is loaded for a task so I have a start time and an end time. I first attempted to POST the javascript variable via AJAX to the back end, but I couldn't seem to get it to work. Now I am trying to have the javascript variable be sent alongside the session ID as part of a "HiddenField". I am not yet at the point of configuring the page load time script, I am just trying to get the Javascript to talk to WTForms to talk to my database commit. Here is my code currently:
views.py
#app.route('/logpage', methods=['GET', 'POST'])
#login_required
def logpage():
form = LogForm()
if form.validate_on_submit():
timer = request.get_data("timer")
entry = LogData(sessionid=form.sessionid.data, user_id=current_user.get_id(), starttime=form.testvar.data, endtime=datetime.utcnow())
db.session.add(entry)
db.session.commit()
return redirect(url_for('home'))
return render_template('logpage.html', form=form)
models.py
class LogForm(FlaskForm):
sessionid = StringField('sessionid', validators=[InputRequired(), Length(min=16, max=16)])
testvar = HiddenField('testvar')
logpage.html
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Active Log Page{% endblock %}
{% block head %}
<!-- Custom styles for this template -->
<link href="static/css/starter-template.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="{{ url_for('static', filename='jquery.js') }}">\x3C/script>')</script>
<script src="static/js/timer.js?version=25"></script>
{% endblock %}
{% block body %}
<div class="container">
<div class="form-group">
<form class="form-logpage", method="POST" action="/logpage", id="jsinput">
{{ form.hidden_tag() }}
{{ wtf.form_field(form.sessionid) }}
<div id="jsinput">
{{ wtf.form_field(form.testvar) }}
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Finish Job</button>
</form>
</div>
</div>
{% endblock %}
timer.js
var myData = "dataVariable";
document.getElementById("jsinput").value = "myData";
As you can see, I tried to use document.getElementById to put the variable in logpage.html, but when I hit submit, the starttime field is empty. I've looked around the documentation for a way to put a variable in the WTForm, but I can't find anything relevant.
Before, during some other issues it's showed as null and /x and ''b but I've done a good bit of tinkering since then and the database entry is just ''.
If there is a more elegant way to record page load datetime and record simultaneously to the database with the rest of the data, I would love to hear suggestions. Previous SO post here: Python/Flask: How to tell how long a user spends on a page? (Data entry/time log app)

Here's the solution I came up with for this problem:
Add a hidden field to the form with an id.
Grab the ID in your script and assign a value to it.
In your form.py:
from flask_wtf import FlaskForm
from wtforms import SubmitField
from wtforms import HiddenField
class MyForm(FlaskForm):
my_data = HiddenField(
'my_data',
render_kw={'id':'my_data'}
)
save = SubmitField(
'Save',
render_kw={'id':'save'}
)
create and pass your form in your view and then render the save and my_data fields in your html template using {{ form.save }} and {{ form.my_data }}
Add the following to your javascript:
var saveButton = document.getElementById('save');
saveButton.addEventListener('click', function() {
document.getElementById('my_data').value = 'MY DATA IS HERE!!';
});
you can now access your data in your python view using:
from flask import request
...some code...
request.form['my_data']
It's a late answer, but hopefully useful to someone out there...

Related

How can I submit multiple forms using Django and JavaScript?

I'm working on an app that displays a form on the index page, into which you can enter information to eventually calculate a gross total and output other details based on the form inputs.
My form inherits from form.Forms.
A button, "Add row", creates as many copies of this row as needed.
Each form contains a form with the ID "calc-form". My problem is that only one form is included in the POST method. I would like to process all forms with one click.
How can I include all additional forms in the POST method when I click "Calculate"?
index.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<script type="text/javascript" src="{% static 'app.js' %}"></script>
<table id="table-id">
<tr id='table-row'>
<form id="calc-form" action="{% url 'result' %}" method="post">
{% csrf_token %}
{% for field in form %}
<td>{{ field|as_crispy_field }}</td>
{% endfor %}
</form>
</tr>
</table>
<br>
<input type="submit" value="Calculate" form="calc-form">
<button type="button" id="add-row-btn" onclick="addRow()">Add row</button>
<button type="button" id="delete-row-btn" onclick="deleteRow()">Delete last row</button>
{% endblock content %}
views.py
from django.shortcuts import render
from .forms import TariffCalcForm
def index(request):
form = TariffCalcForm
context = {'form': form}
return render(request, 'clickapp/index.html', context)
def result(request):
context = {}
if request.method == 'POST':
for r in request:
form = TariffCalcForm(request.POST)
if form.is_valid():
context['form'] = form
return render(request, 'result.html', context)
else:
return render(request, 'index.html', context)
app.js
function addRow() {
const formTable = document.getElementById('table-id');
const formRow = document.getElementById('table-row');
const formRowCopy = formRow.cloneNode(true);
formTable.appendChild(formRowCopy);
}
The form wizard may be appropriate. It allows you to progress through a sequence of forms, storing the results of submitting each in the client's session. This is of course in the database, but it can be made transient, and can be an anonymous session. The final submit can process the data from all the forms and delete it from the session (which may be automatic, not sure) before rendering a results page for the user.
There is limited capacity for skipping some forms based on the data in the previous ones.
The other approach is to go client-based. You use one huge form, but with Javascript of some sort to steer the user through it section by section. "Submit" on earlier parts does not involve the server, but just hides the sub-form and reveals the next (or switches between tabs, which the user may also do for himself). Methods can range from simple Jquery up to enormous Javascript frameworks.

flask javascript can't print/log jinja2 request.form variable

Hi all I'm trying to get the value from flask and print it in javascript.
When I do print with a javascript string variable in my form it prints none.
var javascript_variable = "key_name";
// output is: request
console.log('request'+"{{request.form['"+javascript_variable+"']}}");
Also tried
// output is: request
console.log('request'+"{{request.form["+javascript_variable+"]}}");
however when I manually type the key name it works.
// output is: request key_information
console.log('request'+"{{request.form['key_name']}}");
Can someone please tell me what I'm doing wrong.
EDIT: I do not want to hardcode the keyname because the key_name is a changing dynamically
I'm trying to access that variable, so I can populate my select option/checkbox/radiobox option something like <option {% if request.form['key_name'] == "value" %} selected {% endif %} same for checkbox and radio box
In order to do that, you can use the flash statements inside the views in flask as follows,
#blueprint.route('/something.html', methods=['GET', 'POST'])
#login_required
def function():
try:
flash("Submission successful!")
except Exception as e:
traceback.print_exc()
return render_template('something.html')
In jinja, you can access the flash variable in the following way,
{% if get_flashed_messages() %}
{% for message in get_flashed_messages() %}
<script>window.alert("{{ message }}")</script>
{% endfor %}
{% endif %}

Python/Flask/HTML - Render HTML in new window instead of home page

I have a Python code where I'm using Flask to create a webpage. In the home page, I'm filling out a form, submitting using a button and it displays a table based on the inputs.
The problem i'm having is that once I click the button to submit the form, it renders the table on that same webpage. I would like to create a new window using JavaScript window.open() or whatever other method you might suggest to render that table inside the new window and leave the home page as it is. I tried looking around and I can't seem to get anything to work. I've read through this question and this question. But those suggestions don't seem to match what i'm looking for.
This is my code:
Python code
from flask import Flask, render_template, request,
app = Flask(__name__)
def get_table(user_input):
...
return dict //returns list of dictionaries, for example...
//dict = [{'name':'Joe','age':'25'},
// {'name':'Mike','age':'20'},
// {'name':'Chris','age':'29'}]
#app.route("/")
def home():
return render_template('home.html')
#app.route("/table", methods = ['POST'])
def table():
user_input = request.form['input']
dict_table = get_table(user_input) //return list of dictionaries
return render_template('table.html', dict_table=dict_table)
if __name__ == '__main__':
app.run(debug=True)
home.html
<!DOCTYPE html>
<html>
<head>
<title>Homepage</title>
</head>
<body>
<form action="/table" method="post">
<select name="input">
<option value="1">Input</option>
</select>
<button type="submit">Click Me!</button>
</form>
</body>
</html>
table.html
<!DOCTYPE html>
<html>
<head>
<title>Table</title>
</head>
<body>
<table id="table">
{% if dict_table %}
<tr>
{% for key in dict_table[0] %}
<th>{{ key }}</th>
{% endfor %}
</tr>
{% endif %}
{% for dict in dict_table %}
<tr>
{% for value in dict.values() %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</body>
</html>
Could someone explain in a clear way how I can click the form submit button on my homepage, stay on the homepage home.html, and make the table from table.html open up in a new window (maybe using window.open() from JavaScript or something else)?
I would appreciate it if someone could walk me through the steps on how to do this with my code provided and show me specifically where to call functions and things like that. I'm new to Flask/HTML/JS and I'm just trying to learn for personal use and I'm getting frustrated reading links and documents that show just how to display a URL like google.com in a new tab, which is not what I want. Thanks!
Step1: Check out this link that explains how to use Jquery and Ajax with FLASK
The key concept here is AJAX (asynchronous JavaScript and XML). In short, it is an architecture that makes it possible to send requests to the server in the background (called Asynchronous requests) and then modifies the content of the page currently displayed by the web browser according to the result received from the server, avoiding as well as the server does not transmit the complete page again.
Step2: A solution to your problem
First we write the routes:
from flask import Flask, render_template, request,
app = Flask(__name__)
user_input = None
def get_table(user_input):
...
return dict # returns list of dictionaries, for example...
# dict = [{'name':'Joe','age':'25'},
# {'name':'Mike','age':'20'},
# {'name':'Chris','age':'29'}]
#app.route('/')
def home():
return render_template('home.html')
#app.route('/_ajax_user_input')
def ajax_user_input():
global user_input
user_input = request.args.get('user_input', 0, type=int)
return "ok"
#app.route("/table")
def table():
x = user_input
dict_table = get_table(x) # return list of dictionaries
return render_template('table.html', dict_table=dict_table)
After we attack the templates:
home.html:
<select id="input" name="input">
<option value="1">Input</option>
</select>
<button type="button" class="test"> Click Me! </button>
<script>
$(document).ready(function(){
$('.test').bind('click', function() {
$.getJSON($SCRIPT_ROOT + '/_ajax_user_input',{
user_input: $('#input').val(),
},function() {
window.open('http://127.0.0.1:5000/table', '_blank');
});
return false;
});
});
</script>
table.html:
<table id="table">
{% if dict_table %}
<tr>
{% for key in dict_table[0] %}
<th>{{ key }}</th>
{% endfor %}
</tr>
{% endif %}
{% for dict in dict_table %}
<tr>
{% for value in dict.values() %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Basically here is what happens:
when I click on my button, I call the Javascript script:
$('.test').bind('click', function() {
This sends an ajax request to FLASK, which consists in executing the ajax_user_input() function:
$.getJSON($SCRIPT_ROOT + '/_ajax_user_input',
To this function I send a data (the value selected by the user in the select tag) and this data is stored in the variable user_input:
user_input: $('#input').val(),
On the side of Flask I get the data and I store it in a global variable that I named user_input too:
global user_input
user_input = request.args.get('user_input', 0, type=int)
Then in my script I call a javascript method that allows me to open a url in a new tab (more details here):
window.open('http://127.0.0.1:5000/table', '_blank');
The 'table' route, stores in the variable x the data previously stored in my global variable (user_input), then it calls the function get_table() (by passing him the variable x in parameter) which returns a list of the dictionaries, and finally it returns the page table.html with the list of the dictionaries in parameter:
x = user_input
dict_table = get_table(x)
return render_template('table.html', dict_table=dict_table)
I hope this will help you, even though I am convinced that there are many other ways to do it, perhaps more effective.

How to fire a Javascript alert and then redirect the page after user clicks 'ok' in Django?

I have contact form on my Django website. When someone clicks submit, I would like to use a Javascript alert to inform them that their message has been sent and then redirect them to back to the homepage. I've setup the HttpResponseRedirect part in my view, but I'm struggling to get the JS piece working alongside. Here is my views.py:
from datetime import date
from django.http import HttpResponse, HttpResponseRedirect
from django.template import RequestContext
from django.shortcuts import render_to_response
from .form import ContactUsForm
def contact(request):
form = ContactUsForm(request.POST or None)
if form.is_valid():
this_form = form.save(commit=False)
this_form.save()
return HttpResponseRedirect('/')
return render_to_response('contact/form.html', locals(), context_instance=RequestContext(request))
In your template, you could use something as simple as this (uses some jQuery):
$(function()
{
$('form').on('submit', function(){
alert('Your message has been sent!');
});
});
Note a few things:
This is a little misleading, as it alerts the user that their message has been sent, even
if it doesn't actually get sent (it never checks with the server to make sure). So, if there was some error in the form, this would definitely mislead the user.
This alert will bind to any form on the page, so it may be better to target the specific form with its id.
So that's the quick-and-dirty solution. I'd recommend, though, using Django's messages framework instead. Basically, you'd not use any Javascript to submit the form, but instead add something like this to your view:
from django.contrib import messages
messages.success(request, 'Message sent.')
And then in your template (best to add this to your base template so it shows up wherever the user goes, since messages expire with every page-load:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}

Django - Update page with ajax data

[Edited for more clarity]
My problem is more of an architecture problem, I have thoughts of many ways to do what I need to but can't figure out which one is correct/the best, so here it is.
I fetch some xml from a remote webserver using ajax, then parse it with jquery.What I want is that when the page is first rendered I have some "loading" gifs, one for each ajax request i'll be making , then when the data is fetched, it appears on the page.
The things is I want to have jquery post these data to the view to render it. ( This is for the other developers who will be using my app, who don't know much of javascript and prefer to write python/html to code the way they want the data to be displayed and make use of the django template engine for custom tags and stuff)
The question is how can I distinguish between the first loading of the page where we have no data and the second time where we have the data. I don't want to have to refresh the page at any time. I thought of having something in the template like :
{% block content %}
{% if not data %}
it's the first loading of the page,we have to fetch the data.
<p> My first item : some loading logo </p>
<script>
call a static script that gets the data then appends it to the html/post it back.
</script>
{% endif %}
{% if data %}
the data had already been fetched so we can display it, something like :
<p> My first item : {{first item}} </p>
{% endif %}
{% endblock %}
I have looked on other questions but it is usually updating with data from the database. Sorry if the question is too specific but I want to really have a good design of the problem before starting to write code and I'm a bit lost. Thank you .
Why do you want to send the parsed data back to the server just for transforming it into Html ?
Why not just use some kind of Javascript based rendering library that can do this ? Your appliation would perform faster since you don't need to execute an extra request.
Django tags and context dict are resolved when template is rendered for the first time.
AJAX is used to post/fetch data withoud page reload, so after AJAX request your page will not be reloaded - and django template renderer will have no possibility to show updated data.
But you could use jQuery get() or post() to retrieve rendered template from other django view and integrate it into current page.
This template must be rendered at request on /ajax/fetch/:
{% block content %}
{% if not data %}
it's the first loading of the page,we have to fetch the data.
<p> My first item : some loading logo </p>
<script>
call a static script that gets the data then appends it to the html/post it back.
</script>
{% else %}
the data had already been fetched so we can display it, something like :
<p> My first item : {{first item}} </p>
{% endif %}
{% endblock %}
And this is sitting on your main page:
<script [include jquery here]></script>
<script>
$(function(){
$("#get_data_please").click(function(){
$.get('/ajax/fetch/', function(data) {
// this is called on ajax success
$('#ajax_result').html(data);
});
});
});
</script>
...
Click to get data
<div id="ajax_result">
Here all will be loaded
</div>

Categories