I have a sign out form. Users click a button to secure a reservation. That button changes from “free” to “reserved”, the reserved button includes the user’s name. I’m using Django, but added JS so that the button will change without a refresh.
This works fine on my local server, but when I deploy to PythonAnywhere it doesn’t. Instead, the button transforms, but displays “none” and my console check is “undefined”.
Any idea what went wrong?
Abridged code below:
Main.JS
$( 'button' ).click(function() {
console.log( 'we clicked!' ); // Sanity Check II
var pk = this.id
var button = $(this)
var user = $( 'button' ).attr("user")
console.log( pk, user) // Sanity Check III
$.ajax({
url: "/reserve/",
type: "POST", //Send the info to reserve view
data: { pk : pk},
success: function(data) {
var number = JSON.parse(data);
console.log(number, number.result)
if (number.result == 1 ) {
if (number.result == 2) {
console.log(user)
$(button).toggleClass( "free reserved")
$(button).children("div.tchr").html(user); //Send user info to button, reverts on refresh
$.toast({
heading: "Reservation Complete!",
icon: 'success',
stack: 4,
hideAfter: 2000
});
}
And a button
home.html
{% for p in periods %}
<td class="slots">
Period {{p}} <br>{% for x in this_week %} {% with d=x.day|date:"w" %} {% if d == '1' and x.period == p %} {% if x.is_reserved == True %} # this_week is the queryset of reservations, day is the day converted into a weekday
<button id="{{x.pk}}" type="submit" class="reserved btn">
<span class="cart">{{x.cart}}</span>
<div class="tchr" style="text-align:left">{{x.teacher}}</div></button> {% else %}
<button id="{{x.pk}}" type="submit" user="{{request.user }}" class="free btn">{% csrf_token %}
<span class="cart">{{x.cart}}</span>
<div class="tchr">{{x.teacher}}</div></button> {% endif %} {% endif %} {% endwith %} {% endfor %}
</td>
{% endfor %}
There are a few more options (Cleared, Reserved, Blocked)
Again, this works fine in development! What am I missing?
You need to serve your static files.
Javascript files count as static files. In Development environment, when DEBUG is set to true inside your settings.py files, Django takes car of collecting your static files and serving them, however when you turn DEBUG to false in your deployment server it stops.
Take a look at staticfiles app documentation on Django project to know how to use it. This is a simple static files server that you can use.
To make sure that this is your problem, navigate to your settings.py file and turn DEBUG to true then restart your server. If everything works as expected, follow the instructions on the link above.
Make sure not to rely on DEBUG mode since it could cause performance degradation and massive memory leaks
Related
Problem
I'd like to add a small bit of client-side JavaScript to my Eleventy website. I can't seem to access document. using Eleventy which means I can't access elements and listen to them for events. Example of what doesn't work:
const formElement = document.querySelector("form")
The error message I receive from Eleventy:
ReferenceError: document is not defined
Question
How do I work with Eleventy in order to listen to document element changes and make page changes?
Example:
formElement.addEventListener("change", function () {
// Update nearby paragraph element based on form value
});
My real-world scenario: I would like to have a paragraph element display which of the form's input type="radio" has the value checked.
Approach so far
I have a file in /data called fruits.json:
{
"items": [
{
"name": "Apple"
},
{
"name": "Banana"
},
{
"name": "Strawberry"
},
{
"name": "Mango"
},
{
"name": "Peach"
},
{
"name": "Watermelon"
},
{
"name": "Blueberry"
}
]
}
And a HTML file in /_includes/layouts based on my base.html file:
{% extends "layouts/base.html" %}
{% block content %}
<form>
{% for item in fruits.items %}
{# Create a radio button for each, with the first one checked by default #}
<input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
<label for="{{ item.name | slug }}">{{ item.name }}</label>
{% endfor %}
{% set selectedFruit = helpers.getSelectedFruit() %}
<p>Currently selected item from above is: {{ selectedFruit }}</p>
</form>
{% endblock %}
Note that thee variable called selectedFruit is assigned to a helper function:
{% set selectedScreen = helpers.getSelectedScreen() %}
That getSelectedScreen() function looks like:
getSelectedScreen() {
const formEl = document.querySelector("form")
console.log(formEl)
}
Aside from not being able to work with .document, I feel like this approach is probably 'against the grain' of Eleventy, static site generators in other ways:
The script is being called mid-document
The script is one-off and away from its context
I wonder if I'm approaching this wrong in the first place, or if I just need to do something to allow .document access.
There are some misconceptions here — the most important distinction for your JavaScript code is whether it's executed at build time or client-side at runtime.
The Eleventy core as well as your .eleventy.js configuration file are written in JavaScript which is executed once during the build step, i.e. when your static site is being generated. This happens in a NodeJS environment, not in a browser, which is why there's no document variable and and no DOM.
If you want to dynamically change something on your site in response to user interaction, you need to write a separate JavaScript file which is copied to the output directory of your static site. Then you can include it in the HTML template for your static sites so it's included during normal page visits after your site is deployed.
First, modify your template to only generate a placeholder element for your JavaScript function to add text to later:
{% extends "layouts/base.html" %}
{% block content %}
<form id="fruits-form">
{% for item in fruits.items %}
{# Create a radio button for each, with the first one checked by default #}
<input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
<label for="{{ item.name | slug }}">{{ item.name }}</label>
{% endfor %}
<p id="selected-fruits-output"></p>
</form>
{% endblock %}
Then, create a JavaScript file which reacts to change events on the form:
// fruit-form.js
const fruitForm = document.getElementById('fruits-form');
const formOutput = document.getElementById('selected-fruits-output');
fruitForm.addEventListener('change', e => {
// update the formOutput with the list of selected fruits
});
Now you need to make sure this javascript file is copied to your output directory, using Passthrough file copy:
eleventyConfig.addPassthroughCopy("path/to/fruit-form.js");
Finally, make sure to include the script element in your HTML template (make sure the path is an absolute path to the output as specified above):
{# layouts/base.html #}
<script src="/path/to/fruit-form.js" defer></script>
Now it should work as expected. In general, make sure to understand the difference between build-time and runtime JavaScript, so you can decide which will work best in different situations.
I have developed a Flask website, which I need to trigger different alert messages depending on customers' salary after clicking on a button. I am doing the if statement inside the HTML using the Jinja2 template and according to condition triggers the id and then use this id to trigger an event using JQuery. I believe I am doing something wrong since nothing is happening after I click on the button.
Following is part of my code:
<div>
{% if ((current_user.salary)>=2000 and (current_user.salary) <=5000) %}
<div id="msg0"></div>
{% endif %}
{% if ((current_user.salary)>=1000 and (current_user.GPA) <2000) %}
<div id="msg1"></div>
{% endif %}
</div>
JQuery Code:
$( document ).ready(function(){
$("#second").unbind('click').bind( 'click', function() {
$('#msg0').alert("Your salary is above 2000");
$('#msg1').alert("You salary is less than 2000");
});
});
I did not include the code for designing the button since it is irrelevant I can click on the button. However, I do not think what I am doing with ` is correct. Maybe my JQuery code is not correct.
I would appreciate it if anyone can help me.`
Consider the following code.
$(function(){
$("#second").off('click').click(function() {
if($("#msg0").length){
alert("Your salary is above 2000");
}
if($("#msg1").length){
alert("You salary is less than 2000");
}
}
});
You need to check which of these elements exist in the DOM. To do this, we can check if the jQuery Object has length of 1 or higher.
I am trying to use a javascript variable in a python dictionary in html, is this possible? Any help would be great.
e.g if I had a dictionary - current_data
var num_key = "4";
alert( {{ current_data[num_key] }} );
If I do the following it works perfectly,
alert( {{ current_data["4"] }} );
But with the javascript variable, it won't work.
Thanks again.
No, while you can use Jinja to create JavaScript embedded in <script> tags, you cannot use it the other way around. When Flask renders this page it's static. The page does not still have blocks of code inside {{ }} or {% %}, it holds the result of those operations. However, there are other options. You could put the contents of current_data into hidden input with the keys as the id attributes.
View
{% for key in current_data %}
<input id="{{ key }}" type="hidden" value="{{ current_data[key] }}"/>
{% endfor %}
JavaScript
var num_key = "4";
alert(document.getElementById(num_key).value);
One extra piece of advice, it's not good practice to embed JavaScript into your html. You should have a separate .js file containing this and then include it in your html.
I'm developing a Flask application that contains a ton of inputs. Some the inputs depend on other inputs so there is some DOM manipulation to expose these dependent inputs. I would like for the application to remember the DOM state when the user goes back so the user doesn't have to reenter everything. What's the best way to do this?
Below demonstrates what I think should work. I have an input box that takes a number. There is also a button that adds the same input field to the DOM. When the user clicks submit, these inputs are appended to input_list and the list is displayed on the UI. Because input_list is a global variable, the application will remember these inputs and their values (even if I go back in the browser or reload the page) - this is what I'm looking for.
Again, I'm not sure if this is the best way to do it. I know flask.g can be used to store application globals but I'm not sure this is the right use case for that (I've only seen that used to store database connections). I've also heard cookies may be useful for remembering changes in the DOM. Any thoughts/examples would be helpful and if anyone thinks my way is okay, I'd appreciate feedback on my code below.
app.py:
#app.route('/input_page', methods=['GET', 'POST'])
def input_page():
global input_list
input_list = []
if request.method == 'POST':
if request.form.get('empty_list'):
input_list = []
elif request.form.get('submit_list'):
input_list = [int(i) for i in request.form.getlist('x')]
return render_template('input_page.html', input_list=input_list)
input_page.html:
<p>{{ input_list }}</p>
<form method="POST" action="/input_page">
<div id="input_container">
{% if input_list %}
{% for i in input_list %}
<input type="number" name="x" value="{{ input_list[loop.index0] }}">
{% endfor %}
{% else %}
<input type="number" name="x">
{% endif %}
</div>
<button type="button" id="add_input">Add Input</button>
<input type="submit" value="Submit List" name="submit_list">
<input type="submit" value="Empty List" name="empty_list">
</form>
<script>
$(document).ready(function(){
$('#add_input').click(function(){
var $new_input = $('<input>', {type: 'number', name: 'x'});
$('#input_container').append($new_input);
});
})
</script>
You seem to be on the right track. However, I would shy away from a global variable because that essentially exposes the variable to other concurrent clients. I would however, recommend using the Flask session object:
from flask import Flask, session, ... # other flask modules you already have imported
Then in your Python code, you'd use:
def input_page():
if request.method == 'POST':
if request.form.get('empty_list'):
session['input_list'] = []
elif request.form.get('submit_list'):
session['input_list'] = [int(i) for i in request.form.getlist('x')]
input_list = session.get('input_list', False) # create an input_list var that either grabs the 'input_list' object from the session object or defaults to False if no key found
return render_template('input_page.html', input_list=input_list)
For example, if I have this code:
<form action="{{ url_for('user.new_domain') }}" class="form" role="form" method="post" action="" autocomplete="off">
{{ form.csrf_token }}
<p>{{ form.name(placeholder="name", onkeyup="timing()") }}
<span class="error">
{% if form.name.errors %}
{% for error in form.name.errors %}
{{ error }}
{% endfor %}
{% endif %}
</span>
</p>
</form>
timing() is a function within a javascript file that I have inside a <script> tag in my code. I want timing() to be able to access my sqlite database info and check to see if whatever the user entered into the form exists in my database. Is this even the right way to do this? Through javascript? how else am I supposed to run javascript functions that are dependent on sqlite data? Any help is appreciated. Thanks!
Use Ajax to send a call to another route in your app that returns a string (plain or JSON, whichever is more useful). The Ajax call then uses it's success function to parse that data and act on it as appropriate.
So, in addition to your code that is only rendered by Flask:
{% if form.name.errors %}
{% for error in form.name.errors %}
{{ error }}
{% endfor %}
{% endif %}
you'd need to act via JavaScript:
<script>
function timing() {
$.ajax({
method: "POST",
url: "some url",
data: {
key: "value"
},
success: function(data) {
// do something
}
});
}
</script>
and the code in your app would be something like (based on the fact that your results are coming from another Python file that actually does the querying):
from that_other_file import the_querying_function
#app.route('/some_url', methods=['POST'])
def some_url():
return the_querying_function(request.POST['key'])
This uses HttpResponse.POST. Replace key (in the JS and Python) with whatever you're trying to get from the form.
Short answer is yes it is possible but on limited browsers, see the link for details. http://html5doctor.com/introducing-web-sql-databases/
Long answer is it might be smart to use your backend to access these (perhaps through an API?) Here's one such example for Flask (although I am not sure what you are using https://flask-restless.readthedocs.org/en/latest/)