I am using Boostrap-Flask (not Flask-Bootstrap) with Bootstrap 5.
When I save a form I can use Flash to display an alert using the Bootstrap-Flask macro render_messages
This works fine. However, I'd like to use a Toast rather than an Alert.
I tried doing this via Javascript rather than using flash. This triggers when I hit the submit button. But the toast flashes very fast due to the Flask page reloading on save, I only actually see it if I put an alert("saved") before it in my javascript which delays the page reload just long enough to see the toast flash up. So it is displaying but vanishes immediately on the page refresh. I don't understand why an alert can be sent and displayed but a toast cannot.
function validateForm() {
let toastAlert = document.getElementById('toastAlert');
let toastBody = document.getElementById('toastBody');
let toasticon = document.getElementById('toasticon');
let requested_by = document.forms["form"]["requested_by"].value;
option = {"autohide": false};
toasticon.classList = "h4 bi bi-check2-circle align-middle";
toastAlert.classList = "toast align-items-center text-white bg-success border";
toastBody.innerHTML = " Ticket Saved!";
let toast = new bootstrap.Toast(toastAlert, option);
toast.show();
return true;
};
I have also tried this in my html page:
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
<div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="me-auto">Message</strong>
<small>11 mins ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
{{ message }}
</div>
</div>
</div>
{% endfor %}
{% endif %}
{% endwith %}
as per this SO answer Is there a way to use Bootstrap toast in Flask flashing natively?
But it does not work.
Is this possible?
I got this working by putting the following code into an HTML file and importing this into my base.html
<!-- Begin alerts -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<script>
option = {"autohide": true, timeout:1500};
toastAlert.classList = "toast align-items-center text-white bg-{{category}} border";
toasticon.classList = "toast-icon-{{category}}"; <!-- defined in styles.css -->
toastBody.innerHTML = "{{ message }}";
let toast = new bootstrap.Toast(toastAlert, option);
toast.show();
</script>
{% endfor %}
{% endif %}
{% endwith %}
<!-- End alerts -->
I also have this in a separate HTML file that I import in my base.html
<!-- Toast Notification t-->
<div id="toast-pos" class="toast-container position-fixed top-0 start-50 translate-middle-x p-3" style="z-index: 1099">
<div id="toastAlert" class="toast align-items-center text-white bg-danger border" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
<div class="hstack gap-3">
<span id="toasticon" class="toast-icon-danger"></span>
<span id="toastBody" class="ms-auto h5 text-center align-middle" >Hello, world! This is a toast message.</span>
</div>
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
I created some css to change the icons depending on the Flash category:
.toast-icon-success::before {
font-size: 3rem;
content: "\F26A";
font-family: 'bootstrap-icons';
}
.toast-icon-danger::before {
font-size: 3rem;
content: "\F336";
font-family: 'bootstrap-icons';
}
.toast-icon-info::before {
font-size: 3rem;
content: "\F332";
font-family: 'bootstrap-icons';
}
.toast-icon-warning {
font-size: 3rem;
content: "\F33A";
font-family: 'bootstrap-icons';
}
I can now Flash messages from Flask and they are displayed as Bootstrap toasts.
Related
Here i am trying to pass the value outside for loop modal using ajax
here is my template.html
{% for compliance in compliance %}
{% complience_category compliance request.user as compliances %}
{% for qualification in compliances %}
.....
.....
<td>
<button data-id="{{ qualification.id }}" type="button" class="btn btn-warning margin-bottom edit-qualification">
edit
</button>
</td>
....
.....
{% endfor %}
{% csrf_token %}
<div class="modal hid fade" id="modal-default">
<form class="form-horizontal" method="POST" enctype="multipart/form-data" action=" {% url 'update_qualifications' qualification.id %}">
{% csrf_token %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>Update Compliance</h3>
</div>
<div class="modal-body">
<div class="control-group">
<label class="control-label" for="inputdate_{{qualification.id}}">Expiry Date</label>
<div class="controls">
<input type="date" id="inputdate_{{qualification.id}}" name="expiry_date" value="{{qualification.expiry_date|date:'Y-m-d'}}">
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal">Close</button>
<button class="btn btn-primary" type="submit">Save</button>
</div>
</form>
</div>
{% endfor %}
This is my AJAX
$(document).on('click','.edit-qualification',function(){
var id = $(this).data('id');
$.ajax({
url:'',
type:'POST',
data:{
'id':id,
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
},
success:function(data){
$('#edit_modal .modal-dialog').html($('#edit_modal .modal-dialog',data));
$('#edit_modal').modal('show');
},
error:function(){
console.log('error')
},
});
});
</script>
Here my modal is outside of for loop
Here my problem is when i click the edit button my modal popup is not working (it means when clicking the edit button nothing works for me )
Here my modal is outside of for loop
From the looks of this, the modal is still inside of a for loop.
{% for compliance in compliance %}
...
...
# your modal is here...
{% endfor %}
I'd suggest placing the modal outside of the loop.
Another thing to note is that using Ajax here is really unnecessary unless I'm not understanding what's your purpose for using it.
However, for the edit button, I'd suggest that you add two attributes; data-toggle and data-target. Example:
<button data-toggle="modal" data-target="#myModal">
edit
</button>
In your case, you have for the modal div an id: id="modal-default". This should be assigned to your button's data-target attribute. data-target="#modal-default".
So what you should have instead for the edit button is:
<button data-toggle="modal" data-target="#modal-default" data-id="{{ qualification.id }}" type="button" class="btn btn-warning margin-bottom edit-qualification">
edit
</button>
Ideally, that should work to display the modal.
As for the question of how to pass the values to the modal if a specific edit button is clicked, then I'd suggest you see this answer here as it might be very useful.
Based on this tutorial
This is my views:
def All( request ):
p=product.objects.all().order_by('id')
pa=Paginator(p,20)
page=request.GET.get('page')
pro=pa.get_page(page)
return render(request,'home.html',{'pro':pro})
This is my template:
<div class="grid">
{%for p in pro%}
<div class='card'>
<img src="{{p.image}}"></img>
<p id="id">{{p.description}}</p>
<a href="{{p.buy}}" target='_blank' rel='noopener noreferrer'>
<button ><span class="price"> ${{p.price}}</span> buy</button>
</a>
</div>
{%endfor%}
{% if pro.has_next %}
<a class='more-link' href="?page={{pro.next_page_number}}">Next</a>
{% endif %}
<div class="loading" style="display: none;">
Loading...
</div>
<script>
var infinite = new Waypoint.Infinite({
element: $('.grid')[0],
onBeforePageLoad: function () {
$('.loading').show();
},
onAfterPageLoad: function ($items) {
$('.loading').hide();
}
});
</script>
</div>
I have downloaded dependencies correctly and I included some links in my html to use them, but currently I'm not able to find what is wrong with my code.
server response
Why can't I see Loading... while scrolling?
I'm making a simple website using bootstrap and django.
I tried to put a background image in a container, it loads the image but the image is getting cut off and I don't know what would be the solution.
It's just a standards login page with a background image what I'm trying to making. here is the code.
{% extends "pages/base.html" %}
{% load bootstrap5 %}
{% block header %}
<div="container my-5">
<div class="bg-image p-4 rounded" style="background-image:url('https://i.pinimg.com/originals/29/59/a7/2959a7ef45d681584b984c914c0864fc.jpg');
height: 100vh;">
<h2 class="text-center display-6"> Log in </h2>
<form method="post" action="{% url 'users:login' %}" class="form" style="max-width: 400px; margin:0 auto;">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button name="submit" class="btn btn-dark">Log in </button>
{% endbuttons %}
<input type="hidden" name="next" value="{% url 'my_websites:home'
%}" />
</form>
</div>
</div>
{% endblock header %}
here the original image: https://i.pinimg.com/originals/29/59/a7/2959a7ef45d681584b984c914c0864fc.jpg
thank you so much for your response.
Try this one ✌️
style="background:url('https://i.pinimg.com/originals/29/59/a7/2959a7ef45d681584b984c914c0864fc.jpg') no-repeat center center fixed; -webkit-background-size: cover; -moz-background-size: cover; -o-background-size: cover; background-size: cover; height: 100vh;"
I am a beginner in studying Python Django and I am trying to create a login page for my website using crispy forms. But I can't control the styling of it, I am wondering if it is possible and if it is, how can I possibly do it? Thanks.
Here is the Django HTML codes:
{% extends 'users/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<link rel="stylesheet" href="{% static 'users/register.css' %}">
<div class="register-container">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Create An Acount
</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">
Sign Up
</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">
Already Have An Account?
<a class="ml-2" href="#">Log In</a>
</small>
</div>
</div>
{% endblock content %}
CSS:
base.css
transition: margin-left .5s;
padding: 16px;
background: rgb(255,255,255);
background: radial-gradient(circle,
rgba(255,255,255,1) 0%,
rgba(33,208,178,1) 100%);
}
Yes its possible, you can simply add javascript code which adds class to desired input field and then you can add styling for that class.
For e.g :-
# if you want to add styling to the username input then
# use this javascript
const inp_field = document.querySelector("#input_username"); # enter the id/class of that element
inp_field.classList.add("custom__css");
# css code
.custom__css {
# whatever css you need
}
I am using Flask with WTforms. I am also using the WTFRecaptcha plugin in order to use Captcha fields.
Turns out I need to use two forms on the same page. When I assign a captcha field on each form, one of the captchas is not rendered on the .html page. This is because the captcha is ALWAYS created with the same ID:
Captcha and forms declaration on my forms.py file:
from wtforms import PasswordField, StringField, validators, widgets, RadioField
from wtforms.form import Form
from wtfrecaptcha.fields import RecaptchaField
class FirstForm(Form):
"""First Form"""
#Omitting fields here
captcha_1 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
class Secondform(Form):
"""Second Form"""
#Omitting fields here
captcha_2 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
Route declaration:
#!/usr/bin/env python
from flask import Flask, render_template, request
from flask.ext.assets import Environment
from forms import FirstForm, SecondForm
from flask import request
from flask import jsonify
#app.route('/test')
def test_form():
"""Test."""
form_1 = FirstForm(request.form, captcha_1={'ip_address': request.remote_addr})
form_2 = SecondForm(request.form, captcha_2={'ip_address': request.remote_addr})
if request.method == 'POST' and (form_1.validate() or form_2.validate()) :
return "Instructions have been sent to your e-mail"
return render_template(
'test-form.html',
title='Get Started',
form_1=form_1,
form_2=form_2
)
test-form.html
{% extends "base.html" %}
{% block content %}
<div class="container block-form">
<div class="row first">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_1 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
<div class="row second">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_2 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
Code rendered for captcha in form_1 (Up to the div element):
<script src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" type="text/javascript">
//Other code here omitted
<script src="https://www.google.com/recaptcha/api/js/recaptcha.js" type="text/javascript">
//Other code here omitted
<div id="recaptcha_widget_div" class=" recaptcha_nothad_incorrect_sol recaptcha_isnot_showing_audio">
Code rendered for captcha in form_2 (Up to the div element):
<script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp">
<script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha.js"/>
<div id="recaptcha_widget_div" style="display: none;"/>
<noscript><iframe src="https://www.google.com/recaptcha/api/noscript?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" height="300" width="500" frameborder="0"></iframe>
<br> <textarea name="recaptcha_challenge_field" rows="3" cols="40"> </textarea> <input type="hidden" name="recaptcha_response_field" value="manual_challenge"></noscript>
RESULT: Only one captcha is shown.
... Therefore if I have two captcha fields (Possible on two different forms), one won't display.
Any solutions/suggestions?
This is well a well documented limitation of Recaptcha
Currently, the Google captcha mechanism offer only one captcha form per page
I would encourage you to rethink the way you are organizing your page. Forms in HTML are simple by design. Most of the tooling built around them assumes that a page does one thing and submits the result to the server in a single form submission.
Disclaimer: I don't really know anything about your code. Proceeding regardless: it smells like your design might be a too clever. What I mean by this is that if you haven't seen it done somewhere else and google's tooling doesn't support it the issue is probably with your approach.
If you need to commit the result of a single stateless transaction then a <form> is appropriate and WTForms is a great tool to generate it. If you need something richer you might consider the following:
Break your forms out into multiple pages. A simple set of hyperlinks can provide an easily navigable hierarchy.
Build your DOM with javascript and submit to a RESTful endpoint(you can even use WTForms for validation by converting the request body into a MultiDict and Recaptcha supports AJAX)
Build your <form> dynamically with javascript and switch the action to correspond to the correct form processor on your server.
This is not possible with reCAPTCHA.
See the related ASP.NET question: Multiple reCAPTCHAs in one ASP.Net page
And for possible workarounds: How do I show multiple recaptchas on a single page?