Hide/Show form on button click in Flask - html

I was learning to create a wtf Flask web form which was:
class Update(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
pic = FileField('Update Profile Pic', validators=[FileAllowed(['jpg','png'])])
submit = SubmitField('Update')
What I wanted to do was that the form would load on the same page on a button click without making a seperate html page for the form. How can it be done either by using Flask or HTML? If any changes to route have to be made, please mention that as well.
HTML Code:
<div class="content-section">
<form method="POST" action="" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Account Info</legend>
<div class="form-group">
{{ form.username.label(class="form-control-label") }}
{% if form.username.errors %}
{{ form.username(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.username.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.username(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.email.label(class="form-control-label") }}
{% if form.email.errors %}
{{ form.email(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.email(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.pic.label() }}
{{ form.pic(class="form-control-file") }}
{% if form.pic.errors %}
{% for error in form.picture.errors %}
<span class="text-danger">{{error}}</span><br>
{% endfor %}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>

You can load your form normally, and set it's visibility to hidden. If someone clicks on the button, just change visibility of a form to visible.
Example below:
function toggle_display(){
el = document.querySelector('.content_section');
if(el.style.visibility == 'hidden'){
el.style.visibility = 'visible'
}else{
el.style.visibility = 'hidden'
}
}
<button onclick="toggle_display()">Toggle display</button>
<div class="content_section">See me no more</div>
EDIT:
One more thing to mention, visibility property when set to hidden takes up space, even if it's hidden. To completly remove space that form will take and hide form, set display property to none. To show it again, set display to block.

Related

Formset not showing label in django

I am developing a domestic worker booking app in django
When I try to pass the formset, I am not geting the label of that field. I am only getting the field in html.
{% for formset in formsets %}
<form method="post">
{% for form in formset %}
{% for field in form %}
<div>
<label for="{{ field.auto_id }}">{{ field.label }}</label>
{{ field }}
{% for error in field.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endfor %}
{% endfor %}
<input type="submit" value="Submit">
</form>
{% endfor %}
This the html code
def staffApply(request,pk):
if request.method == 'POST':
selected_domestic_works = request.POST.getlist('domestic_works')
formsets = []
if 'cook' in selected_domestic_works:
formsets.append(CookingForm(request.POST,prefix='cook'))
if 'driver' in selected_domestic_works:
formsets.append(DriverForm(request.POST,prefix='driver'))
print(formsets)
return render(request, 'staffApply2.html', {'formsets': formsets})
return render(request,'staffapply.html',{'uid':pk})
enter code here
This is my views.py
class CookingForm(ModelForm):
food_cooked=(('veg','veg'),
('non-veg','non-veg'),
('both','both')
)
class Meta:
model = Cook
fields = '__all__'
exclude=['user']
widgets={
'food_cooked':forms.widgets.RadioSelect(),
'type_of_cuisine':forms.widgets.CheckboxSelectMultiple()
}
This is my forms.py
I am getting the fields to type. But I am not getting hte label for those fields. Please help me fix this.
class Cook(models.Model):
food_cooked=(('veg','veg'),
('non-veg','non-veg'),
('both','both')
)
type_of_cuisine=(('NorthIndian','NorthIndian'),
('SouthIndian','SouthIndian'),
('Chettinadu','Chettinadu'),
('Chinese','Chinese'),
)
user=models.ForeignKey(User,on_delete=models.CASCADE)
food_cooked=models.CharField(choices=food_cooked,max_length=30)
type_of_cuisine=models.CharField(choices=type_of_cuisine,max_length=30)
experience=models.IntegerField()
wages_expected=models.IntegerField()
dishwashing_flag=models.BooleanField()
wages_for_dishwashing=models.IntegerField(null=True)
desc=models.TextField(max_length=200)
This is my models.py
You have one extra loop, with the wrong naming so you cannot access {{ field.label }} on your loops its like you are trying something like {{ form.field.attribute.label }}, the correct way would be the following:
{% for form in formsets %}
<form method="post">
{% for field in form %}
<div>
<label for="{{ field.auto_id }}">{{ field.label }}</label>
{{ field }}
{% for error in field.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endfor %}
<input type="submit" value="Submit">
</form>
{% endfor %}
That being said, you can also use Django form rendering options, instead of doing it manually.
{% for form in formsets %}
<form method="post">
{{form.as_p}}
<input type="submit" value="Submit">
</form>
{% endfor %}

sending data from a "form action" to a views function in django

How are you community, I'm a little confused between my newbies and lack of knowledge, I'm working on a small project in Django and I'm also trying to send data from a form action in the html to another view function but I'm not understanding it well How does this work and on top of that I have to send several data not just one and it confuses me even more, I have the following HTML:
{% extends "base.html" %}
{% block content %}
<main class="container">
<div class="row">
<div class="col-md-10 offset-md-1 mt-5">
<form action="/interface/" method="POST" class="card card-body">
<h1>Interface</h1>
<h4>{{ error }}</h4>
<select name="dv">
<option selected disabled="True">Select Device</option>
{% for device in devicess %}
<option>{{ device.id }} - {{ device.name }}</option>
{% endfor %}
</select>
<br>
{% csrf_token %}
<br>
<button type="submit" class="btn btn-primary">Send</button>
</form>
<br>
{% for interface in interfaces %}
<section class="card card-body">
<h2>{{interface.Interface}}</h2>
{% if interface.Description == "" %}
<p class="text-secondary">none description</p>
{% else %}
<P class="text-secondary">{{interface.Description}}</P>
{% endif %}
<form action= "{% url 'send_description' %}"method="POST">
{% csrf_token %}
<input type="text" name="command" class="form-control" placeholder="Change description">
<br>
<button type="submit" class="btn btn-primary align-content-lg-center">Send change</button>
</form>
<br>
{% if interface.Status == "up" %}
<p class="text-secondary">Interface State: 🟢 Free</p>
{% else %}
<p class="text-secondary">Interface State: 🔴 Used</p>
{% endif %}
</section>
<br>
{% endfor %}
</div>
</div>
</main>
{% endblock %}
and aesthetically to better understand the first POST executed like this:
So far everything is perfect, if I press the "Send change" button it redirects me perfectly, the problem is that I need to send various data such as device.id, interface to that function that I am executing in the action= "{% url 'send_description' %} .Interface and also the content of the input that is inside the same form. Could you give me a hand or a guide on where to find the best way?
regards!
Let me start by saying that this would work way better with JS and AJAX. But, to answer your question, data is passed via Django http request object, in your case, since you have several different forms, it is possible to pass this data by adding a hidden field inside each form with the desired value:
<input type="hidden" name="interface" value="{{ interface.id }}">
And fetch this value form the request object in the view:
interface = request.POST.get('interface')
A full example:
models.py
class Device(models.Model):
name = models.CharField(max_length=100)
class Interface(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=100, default='interface description field')
status = models.BooleanField(default=False)
device = models.ForeignKey(Device, on_delete=models.CASCADE, related_name='interfaces')
views.py
from django.core.exceptions import ObjectDoesNotExist
def list_interfaces(request):
devices = Device.objects.all()
interfaces = None
try:
selected_device = Device.objects.get(id=request.POST.get('dv'))
interfaces = selected_device.interfaces.all()
except ObjectDoesNotExist:
selected_device = Device.objects.all().first()
if selected_device:
interfaces = selected_device.interfaces.all()
else:
selected_device = None
context = {
'devices': devices,
'selected_device': selected_device,
'interfaces': interfaces
}
return render(request, 'list_device_interfaces.html', context)
def send_description(request):
command = request.POST.get('command')
device = request.POST.get('seleted_device')
interface = request.POST.get('interface')
print(f'command: {command}')
print(f'device_id: {device}')
print(f'device_id: {interface}')
return redirect('core:list-device-interfaces')
urls.py
from core import views
from django.urls import path
app_name = 'core'
urlpatterns = [
path("list/device/interfaces/" , views.list_interfaces, name="list-device-interfaces"),
path("send/description/" , views.send_description, name="send-description"),
]
list_device_interfaces.html
{% extends "base.html" %}
{% block content %}
<main class="container">
<div class="row">
<div class="col-md-10 offset-md-1 mt-5">
<form action="{% url 'core:list-device-interfaces' %}" method="POST" class="card card-body">
{% csrf_token %}
<h1>Device</h1>
<h4>{{ error }}</h4>
<select name="dv">
<option selected disabled="True">Select Device</option>
{% for device in devices %}
<option value="{{ device.id }}" {% if device.id == selected_device.id %} selected {% endif %}>{{ device.id }} - {{ device.name }}</option>
{% endfor %}
</select>
<br>
<br>
<button type="submit" class="btn btn-primary">Send</button>
</form>
<br>
<hr>
<h2>Interfaces</h2>
{% for interface in interfaces %}
<section class="card card-body">
<h2>{{interface.name}}</h2>
{% if interface.description == "" %}
<p class="text-secondary">none description</p>
{% else %}
<P class="text-secondary">{{interface.description}}</P>
{% endif %}
<form action= "{% url 'core:send-description' %}"method="POST">
{% csrf_token %}
<input type="text" name="command" class="form-control" placeholder="Change description">
<input type="hidden" name="seleted_device" value="{{ selected_device.id }}">
<input type="hidden" name="interface" value="{{ interface.id }}">
<br>
<button type="submit" class="btn btn-primary align-content-lg-center">Send change</button>
</form>
<br>
{% if interface.status %}
<p class="text-secondary">Interface State: 🟢 Free</p>
{% else %}
<p class="text-secondary">Interface State: 🔴 Used</p>
{% endif %}
</section>
<br>
{% endfor %}
</div>
</div>
</main>
{% endblock %}

How to change default background of checkbox using flask and wtforms?

I don't understand where to add the class name so I can change the background color of the checkbox.
form.py
DOMAINS = ['Bakeries', 'Bars and Pubs', 'Butcher Shops', 'Electronics', 'Fashion', 'Fish Shops',
'Flowers', 'Furniture', 'Gelaterias and Sweets', 'Pets', 'Other', 'Restaurants and Cafés', 'Sport',
'Supermarkets', 'Vegetables and Fruits']
class MultiCheckboxField(SelectMultipleField):
widget = widgets.ListWidget(prefix_label=False)
option_widget = widgets.CheckboxInput()
class BuyerForm(FlaskForm):
address = StringField(label='Address', validators=[InputRequired()])
domains_fields = [(x, x) for x in DOMAINS]
domains = MultiCheckboxField(label='Domains', choices=domains_fields)
radius = DecimalRangeField(label='Radius (KM)', default=5, validators=[InputRequired()])
submit = SubmitField(label='Search')
buyer_form.html
<div class="form-group">
{{ form.domains.label(class="form-control-label") }}
{% if form.domains.errors %}
{{ form.domains(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.domains.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.domains(class="form-control form-control-lg") }}
{% endif %}
</div>
I'm looking where to add:
CSS file
.container input:checked ~ .checkmark {
background-color: #e86875;
}
(I took it from w3school)
First of all, the part of the CSS you've taken from the example code will not work on its own. When you look at the complete example, it actually removes the original checkboxes and replaces them with new ones done entirely in CSS so they can look and behave a certain way. This means you will need to include the entire CSS code to make the checkboxes look like in the example and change color when selected.
Once you have that done, you can put this in your buyer_form.html code:
<div class="form-group">
{{ form.domains.label(class="form-control-label") }}
{% if form.domains.errors %}
{{ form.domains(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.domains.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{% for domain in form.domains %}
<label class="container">{{ domain.label() }}
{{ domain() }}
<span class="checkmark"></span>
</label>
{% endfor %}
{% endif %}
</div>

HTML radio button is selecting multiple buttons although 'name' attribute has the same value

I googled for this, and the radio button should have the same 'name' attribute to allow only a single value to be chosen.
So I did, and It's still allowing me to choose multiple values...
I used HTML and Jinja2 templates for this, so the code might be looking a bit strange..
{% if search_keyword == None: %}
<p>Please enter your search keyword</p>
{% else: %}
{% for i in range(0, 10) %}
<form method="POST" action="./search">
<h2>
<input type="radio" name="selected_food" id="{{ i }}" value="{{ search_data["hits"][i]['recipe']['label'] }}">
{{ search_data["hits"][i]['recipe']['label'] }}
</h2>
<h4>
Calroies: {{ '%0.2f'| format(search_data["hits"][i]['recipe']['calories']) }} kcal
</h4>
{% for j in range(0, 40) %}
<p>{{ search_data['hits'][i]['recipe']['ingredientLines'][j] }}</p>
{% endfor %}
</form>
{% endfor %}
{% endif %}
In the above code the loop is creating multiple forms. This is the reason why you're able to select multiple values in radio.
If you can modify your code like this, it will work
{% if search_keyword == None: %}
<p>Please enter your search keyword</p>
{% else: %}
<form method="POST" action="./search">
{% for i in range(0, 10) %}
<div>
<h2>
<input type="radio" name="selected_food" id="{{ i }}" value="{{ search_data["hits"][i]['recipe']['label'] }}">
{{ search_data["hits"][i]['recipe']['label'] }}
</h2>
<h4>
Calroies: {{ '%0.2f'| format(search_data["hits"][i]['recipe']['calories']) }} kcal
</h4>
{% for j in range(0, 40) %}
<p>{{ search_data['hits'][i]['recipe']['ingredientLines'][j] }}</p>
{% endfor %}
</div>
{% endfor %}
</form>
{% endif %}

Add class to double curly brackets

i am using the double curly brackets to import variables into my html from my python code. I was inquiring on how to add class to these curly brackets in order to modify the variable in css. Here is a piece of code I am working on.
<div>
{{ form.username.label(class ='username-label') }}
<div>
{% if form.username.errors %}
{{ form.username }}
<div>
{% for error in form.username.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.username }}
{% endif %}
</div>
I tried to add class into the form.username.label in order to change the appearance of the label but it doesnt work. Is there a way to do it. I want it specifically for that label and not the whole div. I hope the only solution is not to add another div tag to the variable
Let's see, whether I get you correctly.
{{ form.username.label(class_='username-label') }}
should become
{{ form.username.label(class_='username-label with-errors') }}
in case the form is invalid.
I'd approach it with
<div>
{% if form.username.errors %}
{{ form.username.label(class ='username-label with-errors') }}
{% else %}
{{ form.username.label(class ='username-label') }}
{% endif %}
<div>
{% if form.username.errors %}
{{ form.username }}
<div>
{% for error in form.username.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.username }}
{% endif %}
</div>
</div>
Also you could use actual <label> and an <ul> for improving semantics.
Edit: Added underscores, so class_ is applied in a Flask template correctly.