How do I send data from javascript to python flask back-end? - javascript

I know this question has been answered already but I do not understand.
I am new to flask and co-developing a chat website.
This includes a database for users to log in
My signup.html has a considerable size, so I will only include the part I'm having troubles with:
{% extends "base.html" %}
{% block title %} Sign up {% endblock %}
{% block content %}
<form method="POST" id="signupform" action="#" onsubmit="checkForm()">
<div class="form-group row">
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="gridCheck1">
<label class="form-check-label" for="gridCheck1">
I have read and agreed to the Terms Of Service
</label>
<small id="checkSmall" class="form-text text-muted"></small>
</div>
</div>
</div>
</form>
{% endblock %}
My javascript:
function checkForm() {
var isChecked = document.getElementById("gridCheck1").checked
if (isChecked == false) {
console.warn("TOS not agreed to")
document.getElementById("checkSmall").innerHTML = "Please agree to the TOS before continuing.";
} else {
console.log("Tos were agreed to")
}
}
My python (again, not the whole file):
#app.route("/signup", methods=["GET", "POST"])
def signup():
if request.method == "POST":
Name = request.form["Name"]
Email = request.form["Email"]
Password = request.form["Password"]
usr = users(Name, Email, Password)
acc = [Name, Email, Password]
for value in acc:
if len(value) == 0 or " "*len(value) == value:
flash(f"{value} cant be blank")
return redirect(url_for("signup"))
break
elif len(value) > 100:
flash(f"{value} cant be more then 100 chars")
return redirect(url_for("signup"))
break
db.session.add(usr)
db.session.commit()
flash("Signed up.")
return redirect(url_for('home'))
return render_template("signup.html")
I dont want to redirect to the home page unless the user actually agrees.
I already have the javascript set up to pop a little message if they dont check that checkbox, and I need to tell the server to stop from the js.
Could anyone help?
PS: I could also use another way to acheive my goal.
Also, just in case this can help anyone solve my problem, I'm using bootstrap. I'm not good at html, so anything helps.

Simplest way I can think of (I think this will work; anyone correct me if it is wrong):
<input class="form-check-input" type="checkbox" id="gridCheck1" required>

Related

Send data from Javascript → Python and back without reloading the page

I'm trying to make a stock finance like website where anyone can get fake money and buy stocks. So in the buy page, I am trying to implement a feature where as the user types the stock symbol and the number of shares, in real time, the pricing shows up in the h1 tags that have an id of "render". This can be achived if user input is sent to my app.py and after looking up the price using an api and some math, app.py send the price back to javascript to update the page.
I've been trying to use fetch() and AJAX but I don't understand any of the tutorials or stack overflow questions. Can someone give me a reliable solution and explain it to me?
HTML:
{% extends "layout.html" %}
{% block title %}Buy{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="mb-3">
<input class="form-control mx-auto w-auto" autocomplete="off" name="symbol" placeholder="Symbol" value="{{ input_value }}" id="symbols">
</div>
<div class="mb-3">
<input class="form-control mx-auto w-auto" autocomplete="off" autofocus name="shares" placeholder="Shares" id="shares">
</div>
<div class="mb-3">
<button class="btn btn-primary" type="submit">Buy</button>
</div>
</form>
<h1 id="render">
</h1>
<script>
</script>
{% endblock %}
App.py:
#app.route("/buy", methods=["GET", "POST"])
#login_required
def buy():
"""Buy shares of stock"""
if request.method == "GET":
return render_template("buy.html", input_value = "")
else:
return render_template("buy.html", input_value = request.form.get("symbol"))
I'm trying to use the function above for rendering the template
Accepting response and sending back information:
#app.route("/show_price", methods=["GET", "POST"])
def show_price():
#logic stuff
return #price
TL;DR at bottom
I found a solution to the problem by using this as my app.py:
#app.route("/show_price", methods=["GET", "POST"])
#login_required
def show_price():
# https://www.makeuseof.com/tag/python-javascript-communicate-json/
data = request.get_json()
if data[1].isdigit() == True:
data = jsonify() # the data
return data
else:
return ""
and using fetch() in my javascript:
{% extends "layout.html" %}
{% block title %}Buy{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="mb-3">
<input id="symbols">
</div>
<div class="mb-3">
<input id="shares">
</div>
<h2 id="render">
</h2>
<div class="mb-3">
<button class="btn btn-primary" type="submit">Buy</button>
</div>
</form>
<script>
let input1 = document.getElementById('symbols');
let input = document.getElementById('shares');
input.addEventListener('keyup', function(event) {
value = [
input1.value, input.value
]
fetch("http://127.0.0.1:5000/show_price",
{
method: 'POST',
headers: {
'Content-type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(value)}).then(res =>{
if(res.ok){
return res.json()
} else {
document.querySelector('h2').innerHTML = "Keep typing...";
}
}).then(jsonResponse=>{
word = "That would be " + jsonResponse
document.querySelector('h2').innerHTML = word;
})
.catch((err) => console.error(err));
});
</script>
{% endblock %}
so as the user is typing in the the shares field the event listener will get the symbols and shares fields, use fetch() to get the data over to def show_price() with a jsonified array of symbol and shares. If there is an error the div id="render" will display "Keep typing". After python gets the information it will look it up using a function, then it will return the price of the shares in json format. Then javascript will get the data and use some javascript to change the html.
TL;DR
Basically I used fetch() to get the data to python, did some algorithm stuff and python return it to javascript. https://www.makeuseof.com/tag/python-javascript-communicate-json/ is really useful in teaching you how to use fetch().

How to change visibility/display of a html block using flask or vanilla js with submit event?

I created a small flask app and deployed it on Heroku. I'm bad with backend and flask I just can't figure out how to properly display html block of code that should display under the form when it is submitted.
Link to the app: http://alumil-alloys.herokuapp.com/
Link to github repo: https://github.com/nemanjaKostovski/MLmodel
HTML:
<form class="form" action="{{ url_for('main') }}" method="POST">
<label class="label"><input class="input" type="number" step="0.01" name="Rm" placeholder="Rm" required></label>
<label class="label"><input class="input" type="number" step="0.01" name="Rp" placeholder="Rp" required></label>
<label class="label"><input class="input" type="number" step="0.01" name="A%" placeholder="A%" required></label>
<label class="label"><input class="input" type="number" step="0.01" name="Wb" placeholder="Wb" required></label>
<input class="button" type="submit" value="Search">
</form>
<div class="result">
{% if result %}
{% for variable, value in original_input.items() %}
<b>{{ variable }}</b> : {{ value }}
{% endfor %}
<br>
<br> <h3>Suggested alloy:</h3>
<p class="big">{{ result }}</p>
{% endif %}
</div>
<script src="{{url_for('static',filename='main.js')}}"></script>
CSS:
.result {
visibility: hidden;
text-align: center;
padding: 5px;
margin: 5px;
width: 450px;
border: 5px solid gray;
background-color: #ffd300;
}
JS:
const form = document.querySelector('.form');
const result = document.querySelector('.result');
function showResult(){
result.style.visibility = 'visible';
}
form.addEventListener('submit', showResult);
Flask:
#app.route('/', methods = ['GET', 'POST'])
def main():
if flask.request.method == 'GET':
return(flask.render_template('main.html'))
if flask.request.method == 'POST':
max_strength = flask.request.form['Rm']
yield_strength = flask.request.form['Rp']
elongation = flask.request.form['A%']
webster = flask.request.form['Wb']
input_variables = pd.DataFrame([[max_strength, yield_strength, elongation, webster]],
columns = ['Rm', 'Rp', 'A%', 'Wb'],
dtype = float)
prediction = model.predict(input_variables)[0]
return flask.render_template('main.html',
original_input = {'Rm':max_strength,
'Rp':yield_strength,
'A%':elongation,
'Wb':webster},
result = prediction
)
Sorry, I missed the fact that you were already returning your result as key word arguments (you were just doing it differently from me) so I'm going to edit the answer (deleted most of the previous answer and responding based on the information you have provided in a comment.
Based on your current design
The first time you load your page, the result div will not show up
Then you execute a search and the result div will show up. It may or may not contain results
The result div will now always be visible unless you reload the page. If you do a new search, the contents of the result div will be cleared
If you're okay with the above behavior, then you don't even need the JS script. Just modify your code to
{% if result %}
<div class="result">
......
{% endif %}
You can do away with your JS and the visibility style in your CSS
The explanation is
When you load your page, the system executes a GET and your flask code says to return just the template without any variables. The page will thus check for result and since it is not available, it will not display the result div
Then you enter variables and submit the form which does a POST and your flask now returns a result variable which means the result div will now be displayed to the user
If user wants to clear the result div from the UI, they can reload the page or you can add a button or delete icon that when it is clicked, you remove the div from the page

Is it possible to use URL parameters in If Statements for OctoberCMS?

The issue I'm having is that various translations on the page use URL parameters to fill in the content for a form dynamically. The form has radio buttons and I want to have one of them checked by default depending on the URL Parameter.
So for example, if the URL says ?lang=dk, I would want the European radio button to be checked, but if it says ?lang=fr-ca, I'd want it to check North America:
<form id="contact-form" method="post" class="form-contact" enctype="multipart/form-data">
<div id="form-platform" class="form-platform--radio-group">
<label class="radio--button" for="option-na">
<input class="form__input" type="radio" id="option-na" name="platform"
value="NA">
<i></i>
<span class="radio--label">North America</span>
</label>
<label class="radio--button" for="option-eu">
<input class="form__input" type="radio" id="option-eu" name="platform"
value="EU">
<i></i>
<span class="radio--label">Europe</span>
</label>
</div>
</form>
So far, I've tried using this.param but it's been unsuccessful so far.
Is my only option to use Javascript to achieve what I need, or is this possible with OctoberCMS?
For Clarification:
A url like "example.com?lang=us" is making a request on the server. The request is Input::get('lang') = 'us'.
A url like "example.com/:lang?/" is using the Laravel routing system to access parameters of the slug. This would look like "example.com/us/page" and the request looks like this.param('lang') = 'us'.
Both of these could work for your system depending on how you are setting the language.
My recommendation is to design your website with dynamic values in mind and use collections like this.
PHP CODE in CMS page for adhoc:
function onStart() {
$language = Input::get('lang'); //check for a language request
$languages = [ //build language array
'dk' => [
'place' => 'European',
'selected' => false,
'value' => 'eu'
],
'fr-ca' => [
'place' => 'North America',
'selected' => false,
'value' => 'na'
]
];
if (isset($languages[$language])) {
$languages[$language]['selected'] = true; //see if the language request is in the array then set selected to true
}
$this['languages'] = $languages; //return languages to the page
}
In your Markup side of the page you can then do this - With twig you can just make a for loop set the variables and check to see if the language is selected.
<form id="contact-form" method="post" class="form-contact" enctype="multipart/form-data">
<div id="form-platform" class="form-platform--radio-group">
{% for language in languages %}
<label class="radio--button" for="option-{{ language.value}}">
<input class="form__input" type="radio" id="option-{{ language.value }}" name="platform"
value="{{ language.value | upper }}" {% if language.selected %}checked{% endif %} >
<i></i>
<span class="radio--label">{{ language.place }}</span>
</label>
{% endfor %}
</div>
</form>

Trying to create a printable web page in octobercms

Hi I am trying to create a printable page from data send by a form in octobercms
I have created a plugin component which I have called PrintPageForm
<?php namespace Acme\PrintPage\Components;
use Cms\Classes\ComponentBase;
use Input;
class PrintPageForm extends ComponentBase
{
public function componentDetails()
{
// TODO: Implement componentDetails() method.
return
[
'name' => 'Print Page Form',
'description' => 'Detail page print form'
];
}
public function onHandleForm()
{
$var =
[
'overview' => Input::get('print_overview'),
'photos' => Input::get('print_photos')
];
I have this in the default htm file
<form action="/print" data-request-data="printpageform::onHandleForm" data-request-validate data-request-flash accept-charset="utf-8" class="form ajax-form">
<h3 class="sub-heading">Print Details</h3>
<p>To build a printer friendly formatted page, please select from the options shown below:</p>
<ul class="print-section">
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_overview" id="print_overview">
<label class="checkbox-label period" for="print_overview">Overview: Summary and key features alongside a photo of the property.</label>
</li>
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_photos" id="print_photos">
<label class="checkbox-label period" for="print_photos">Photos: Photo gallery of the property.</label>
</li>
</ul>
<input type="hidden" name="print" value="1">
<button class="btn button-large one-third palm-one-whole" type="submit" rel="print" >Print</button>
</form>
I am trying to access the value of print_overview and print_photo values in my print view page but can not figure out how to access these values I can see these values being passed in Debugbar as follows "request_query
array:2 [ "print_overview" => "1" "print" => "1" ]" and in my view file I have
{%if "print_overview" == "1" %}
{{ 'checked' }}
{% else %}
{{ 'Not Checked' }}
{% endif %}
but it does seem to matter what the value of print_overview is the page only echos out Not Checked I'm in a rut that I can't figure out any thoughts would be gratefully accepted.
Couple of pointers. When rendering a form in Twig, you should use either the {{ form_open() }} or {{ form_ajax() }} tags
Secondly, you can access the request data via the post() function in your component class; and you pass it to your view (the component partial) through the page property. So, your handler would like something like:
public function onHandleForm()
{
// Pass the variables to the view renderer
$this->page['print_overview'] = (bool) post('print_overview');
$this->page['print'] = (bool) post('print');
// Return a partial response http://octobercms.com/docs/ajax/update-partials#pushing-updates
return ['#view-response-element' => $this->makePartial('#response')]; 
}
While your response.htm partial file would look something like this:
{% if print_overview %}
"checked"
{% else %}
"not checked"
{% endif %}
As a note, if you are using the {% macro %} tags, these do not have access to the local scope of the partial file, i.e. they do not have access to the variables provided to the view. Any evaluation done within {% macro %} tags needs to be based on variables passed to it.
The best strategy for printing I find is to use JavaScript:
<!-- Link to print -->
<p>Print this invoice</p>
<!-- Invoice printer -->
<script type="text/template" id="invoiceTemplateContents">
Printable contents go in here
</script>
<!-- Script -->
<script>
function printInvoice() {
var printWindow = window.open('','','left=0,top=0,width=950,height=500,toolbar=0,scrollbars=0,status=0')
printWindow.document.write($('#invoiceTemplateContents').html())
printWindow.document.close()
printWindow.focus()
printWindow.print()
printWindow.close()
}
</script>

How can I get the <select> tag option chosen by the user using Flask?

I have a form whereby a user uploads a csv file, that csv file is then converted to a pandas dataframe and the column headers automatically populate the <select> tag options in the form.
I then want the user to select the column that they want and I want that column choice saved in a variable using Flask.
However, I'm having trouble retrieving the option that the user then selects from this select tag.
My template code:
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
<fieldset>
<legend>Text Analytics</legend>
<div class="form-group form-group-lg">
<label for="inputData" class="col-lg-2 control-label">Choose Data File:</label>
<div class="col-lg-5">
<input type="file" class="form-control" required="required" autofocus="autofocus" name="inputData"/>
</div>
<div class="col-lg-3">
<button class="btn btn-primary" type="submit" name="upload">Upload</button>
</div>
{% if success %}
<div class="alert alert-success">
×
<strong>Success!</strong> {{success}}.
</div>
{% endif %}
{% if error %}
<div class="alert alert-warning">
×
<strong>Error:</strong> {{error}}.
</div>
{% endif %}
</div>
<div class="form-group form-group-lg">
<label for="colSelect" class="col-lg-2 control-label">Select column for analysis:</label>
<div class="col-lg-5">
<select class="form-control" name="colSelect" id="colSelect">
{% for column in columns %}
<option id="{{column}}">{{column}}</option>
{% endfor %}
</select>
</div>
My Flask code:
#app.route('/textanalytics', methods = ['GET', 'POST'])
def upload_file():
error = None
success = None
columns = []
col = None
if request.method == "POST":
if request.files['inputData'] == '':
error = "No file selected"
else:
file = request.files['inputData']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
success = 'File uploaded'
data = pd.read_csv(os.path.join(app.config['UPLOAD_FOLDER'], filename), header = 0, low_memory = False)
columns = [i for i in data.columns]
col = request.form.get('colSelect')
return render_template('textanalytics.html', success = success, columns = columns, col = col)
elif file and not allowed_file(file.filename):
error = 'Incorrect file type, .csv only'
return render_template('textanalytics.html', error = error)
return render_template('textanalytics.html', error = error, success = success, columns = columns, col = col)
app.add_url_rule('/uploads/<filename>', 'uploaded_file', build_only=True)
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {'/uploads': app.config['UPLOAD_FOLDER']})
As you can see, I am using request.form.get('colSelect') to retrieve the option but without any luck. It just returns None which is its initialised value.
I have a feeling it has to do with where I am placing that code but I am new to Flask and so could do with some help.
You have to give each option a value.
<option value="{{ column }}">{{ column }}</option>
I managed to figure it out. I took the form and separated it over two pages. So, the File Upload part was in its own form on a page called textform1.html. The uploaded file would be converted to a pandas dataframe and then a new page called textform2.html would be rendered. This page contained just the <select> part in its own form and thus I was then able to capture the selection from the user.

Categories

Resources