Bootstrap dismissable alerts - django

I have a form in my django project and I want to display the form errors if any when the user clicks submit. This is one of my fields (working on getting one right before I move on to others)
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="title">Title
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
{{ form.title }}
</div>
<div class="col-md-3 .col-md-offset-3">
{# <p class="text-danger">{% for error in form.title.errors %}{{ error }}{% endfor %}</p>#}
<div class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<p>{% for error in form.title.errros %} {{ error }} {% endfor %}</p>
</div>
</div>
However I have 2 issues :
The alert shows up when the form loads, without the error message:
When I dismiss the alert the form styling gets messed up:
I cant seem to understand what the issue is.
I was able to get the error message without the bootstrap alerts using this code. However it would be great to let the user dismiss an alert after the correction has been made:
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="title">Title
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
{{ form.title }}
</div>
<span class="help-block">
<p class="text-danger">{% for error in form.title.errors %}{{ error }}{% endfor %}</p>
</span>
</div>

Your <div> containing the alert has no closing </div> tag, that messes up the form when you dismiss the alert. As for the alert showing up when the form loads - there's already some content in the alert div (the 'close' button) so it is displayed. You have to render it conditionally (only when there are corresponding errors to show):
<div class="col-md-3 .col-md-offset-3">
{% if form.title.errors %}
<div class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<p>{% for error in form.title.errors %} {{ error }} {% endfor %}</p>
</div>
{% endif %}
</div>

Related

How can I remove a particular item using a popup?

I have many items and I want to delete one of them but when I delete one item it turns out that it deletes the last item which exists based on ordering so, if I have 10 records of id which start from 1 to 10 record so, it will remove the item number 10 til if I remove item number 5 will remove the number 10. this case occurs because of popup but if I remove popup and delete the items directly it will remove with no mistake so, How can I remove a particular item using popup?
profile.html
{% if request.user == profile.user %}
<div class="col-lg-7 offset-lg-1 col-12">
{% if profile.user.user_history.all.count != 0 %}
<form method="post">
{% csrf_token %}
<div class="clear_all fl-left">
<input class="global_checkbox" type="checkbox" name="remove_all_history" id="remove_all_history">
<label for="remove_all_history" class="ml">Remove All</label>
</div>
<div class="fl-right">
<input type="submit" value="Remove" class="clear_button btn btn-danger invisible"/>
</div>
</form>
{% else %}
<p class="text-center">you have no history yet!</p>
{% endif %}
<div class="clearfix"></div>
<div class="mt-6"></div>
{% for history in history_pages %}
{% if history.deleted_history == False %}
<div class="history">
<div class="row">
<div class="col-4">
<form method="post">
{% csrf_token %}
<input class="global_checkbox" type="checkbox" name="remove_one_history" id="remove_all_history">
<span class="ml-2">{{ history.history_time|time }}</span>
<div class="ml ml-4">{{ history.history_time|date:'d M Y' }}</div>
</form>
</div>
<div class="history-content col-7">
<p><strong>text:</strong> {{ history.history }}</p>
<p><strong>action:</strong> {{ history.action_option }}</p>
<p><strong>position:</strong>
{% if history.verb_option == "" %}
POS
{% else %}
{{ history.verb_option }}
{% endif %}
</p>
</div>
<form method="post" action="{% url 'accounts:remove_history' history.id %}">
{% csrf_token %}
<div class="history-list col-1">
<span class="fa fa-ellipsis-v" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu">
<a type="button" class="dropdown-item" data-toggle="modal" data-target="#exampleModal">Remove this item</a>
</div>
</div>
{% include 'accounts/popup.html' %}
</form>
</div>
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
popup.html
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Warning!!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Do you want to remove this history item?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-outline-danger">Remove</button>
</div>
</div>
</div>
</div>
views.py
#login_required
def userProfile(request, slug=None):
profile = None
try:
profile = Profile.objects.get(user__slug=slug)
paginator = Paginator(profile.user.user_history.all(), 100)
page_number = request.GET.get('page_number')
history_pages = paginator.get_page(page_number)
except:
return redirect('accounts:index_404')
return render(request, 'accounts/profile.html', {'profile': profile, 'history_pages': history_pages})
def remove_history(request, id=None):
if id and id is not None:
# History.objects.get(id=id)
print(id)
return redirect("accounts:profile", request.user.username)
Note: I tested the delete using print(id)
In your current code you have included popup.html mutliple times so when you click on a tag its not confirm which modal will get open has all are triggering exampleModal i.e :data-target="#exampleModal" .
So , to overcome this one way would be including only one modal and adding form tags around submit button . Then , whenever user click on a tag you can get action value from form where a tag has been clicked and then add this action value inside modal form tag .
Demo Code :
//on click of `a` tag
$(".dropdown-item").on("click", function() {
//get closest form from `a` tag then get action from it
var action_ = $(this).closest("form").attr("action");
$("#exampleModal form").attr("action", action_) //add that action inside modal form tag
console.log(action_)
})
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="history">
<div class="">
<div class="">
<form method="post">
{% csrf_token %}
<input class="global_checkbox" type="checkbox" name="remove_one_history" id="remove_all_history">
<span class="">12:30</span>
<div class="">12-04-21</div>
</form>
</div>
<div class="history-content">
<p><strong>text:</strong> Somethigs</p>
<p><strong>action:</strong>Ok</p>
<p><strong>position:</strong> POS
</p>
</div>
<form method="post" action="{% url 'accounts:remove_history' 1 %}">
<div class="history-list">
<span class="fa fa-ellipsis-v" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu">
<a type="button" class="dropdown-item" data-toggle="modal" data-target="#exampleModal">Remove this item</a>
</div>
</div>
<!--remove this line {% include 'accounts/popup.html' %}-->
</form>
</div>
</div>
<div class="history">
<div class="">
<div class="">
<form method="post">
{% csrf_token %}
<input class="global_checkbox" type="checkbox" name="remove_one_history" id="remove_all_history">
<span class="">12:32</span>
<div class="">22-04-21</div>
</form>
</div>
<div class="history-content">
<p><strong>text:</strong> Somethigs2</p>
<p><strong>action:</strong>Ok2</p>
<p><strong>position:</strong> POS
</p>
</div>
<form method="post" action="{% url 'accounts:remove_history' 2 %}">
<div class="history-list">
<span class="fa fa-ellipsis-v" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu">
<a type="button" class="dropdown-item" data-toggle="modal" data-target="#exampleModal">Remove this item</a>
</div>
</div>
<!--remove this line {% include 'accounts/popup.html' %}-->
</form>
</div>
</div>
<!--just use only one modal no need to include it every time on your page-->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Warning!!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<!--added form tag-->
<form method="post" action="">
<!--added csrf token-->
{% csrf_token %}
<div class="modal-body">
Do you want to remove this history item?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-outline-danger">Remove</button>
</div>
</form>
</div>
</div>
</div>

How can I get the validation errors from flask_wtforms

I would like to get validation errors from a textarea form from flask_wtforms. I know that you can get them by including this in the html :
{% for error in form.post.errors %}
{{ error }}
{% endfor %}
But that doesn't quite work for me because Im using a bootstrap modal and the Length validation requires you to submit the form, refreshing the page, unlike the DataRequired() validator which prevents you from submitting. And its hard to tell that the form failed.
Basically I would like to get the errors from the python end and flash them.
I've tried to access the errors with form.post.errors but it doesn't work, it always returns an empty set.
This is the code for my index
def index():
form = PostForm()
// I would like to get the errors via form.post.errors here and I don't understand why I can't
if form.validate_on_submit():
post = Post(body=form.post.data, author=current_user)
db.session.add(post)
db.session.commit()
flash('Your post is now live!', 'primary')
return redirect(url_for('index'))
page = request.args.get('page', 1, type=int)
posts = current_user.followed_posts().paginate(page, app.config['POSTS_PER_PAGE'], False)
next_url = url_for('index', page=posts.next_num) if posts.has_next else None
prev_url = url_for('index', page=posts.prev_num) if posts.has_prev else None
return render_template('index.html', title='Home', posts=posts.items, form=form, next_url=next_url, prev_url=prev_url)
{% extends "base.html" %}
{% block content %}
{% if form %}
<div class="modal fade" id="submitPost" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<form action="" method="post">
{{ form.hidden_tag() }}
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="submitPostLabel">Submit Post</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="PostText">{{ form.post.label }}</label>
{{ form.post(cols=32, rows=4, class="form-control") }}<br>
</div>
</div>
<div class="modal-footer">
<!-- <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> -->
{{ form.submit(class="btn btn-primary") }}
</div>
</div>
</form>
</div>
</div>
{% endif %}
the above html file is basically
<form action="" method="post">
{{ form.hidden_tag() }}
{{ form.post.label }}
{{ form.post(cols=32, rows=4, class="form-control") }}
{{ form.submit(class="btn btn-primary") }}
</form>
with some bootstrap
You can print the errors by adding the following: print form.errors.items().
form.errors

Flask url_for could not build endpoint based on working code. Asks if I want index?

My Flask app already serves up several pages. I just made channels.html. For a route, I copied down and changed /messages, which already works. I then tried adding a link from messages.html to channels.html, but received the error: Could not build url for endpoint 'channels'. Did you mean 'index' instead? The error references the line Channels in messages.html. I checked spelling, syntax, decorator placement, and duplicative names; everything looks ok. Plus, the new code was built off of code that was previously tested.
So, why the error?
#app.route('/channels', methods=["GET", "POST"])
def channels():
return render_template("channels.html")
#app.route('/messages', methods=["GET", "POST"])
def messages():
return render_template("messages.html")
messages.html (top part)
{% extends "layout.html" %}
{% block body %}
<div class="container">
<div class="row" style="min-height: 100vh">
<div class="col-md-3 border border-danger rounded">
<div class="row mt-2 justify-content-start">
Header
</div>
<!-- <div class="row mt-2 justify-content-start" id="channelHeader">
Channels
</div>-->
<div class="row mt-2 justify-content-start" id="channels">
Channels
</div>
<div class="row justify-content-start" id="dmsg">
Direct Messages
</div>
</div>
<div class="col-md-9 border border-danger rounded">
{% endblock %}
channels.html
{% extends "layout.html" %}
{% block body %}
<div class="container">
<div class="display-3">
<strong>Create A Channel</strong>
</div>
<form action="{{ url_for('channels') }}" id="channelForm" class="mt-4">
<!-- Will need check for duplicate email -->
<div class="form-group">
<label for="channelName">Channel Name</label>
<input type="text" class="form-control" id="channelName" aria-describedby="channelName" placeholder="Enter Channel Name">
</div>
<!-- Will need check for duplicate username -->
<div class="form-group">
<label for="inviteUsers">Invite Other Users (optional)</label>
<input type="text" class="form-control" id="inviteUsers" aria-describedby="inviteUsers" placeholder="Search by name">
</div>
<div class="form-group">
<label for="purpose">Purpose</label>
<textarea type="text" class="form-control" id="purpose" rows="3" placeholder="Purpose">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
{% endblock %}

Django, form can not be submitted

I created the form, but i can not submit it using post method. I worked with generic views
When i try to submit it,this link appeares '?csrfmiddlewaretoken=4u6glHHJVueXItlN...'
here's my code:
form template:
<form action="" method="post" class="form-inline">
{% csrf_token %}
<div class="modal-body clearfix">
{% include 'words/word_form.html' %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</form>
generic view:
class Create_Word(generic.CreateView):
model=Word
fields=['name','translation']
template_name = "words/list_all.html"
Here's word_form template:
{%load extra%}
{% for field in form %}
<div class="form-group ">
<div class="col-sm-10">
<span class="text-danger-small">{{ field.errors }}</span>
</div>
<label class="control-label col-sm-2 m-l-1 ">{{ field.label_tag }}</label>
<div class= "col-sm-9 m-b-1">
{{ field | addcss:"form-control" }}
</div>
{% endfor %}

Django eternicode bootstrap-datepicker doesn't work on phones

In my Django app i'm using bootstrap-datepicker. User chooses a date, then date is passed in Ajax post request to /check/ view, then sub_template is reloaded with retrieved data.
Everything works like a charm on desktop, but it seems like datepicker doesn't work on phones at all. I've tested it on Iphone 6s, android phone and windows phone(all default browsers). When i press date it just doesn't respond in any way.
Here is my main page html:
<div class="container">
<div class="row text-center">
<h2>Availability</h2>
</div>
<hr>
<div class="row text-center hidden-xs ">
</div>
<div class="row row-pad-30 text-center">
<div class="col-lg-1 md-hidden"></div>
<div class="col-lg-4 col-md-12 col-sm-12 col-xs-12">
<h3>1. Choose date</h3>
<form style="color: white;" class="form-date" role="form" action="" method="get">
{% csrf_token %}
<div class="form-group" id="datepicker">
<div></div>
<input data-date-format="YYYY-MM-DD" type="hidden" name="dt_due" id="dt_due" val="">
</div>
</form>
</div>
<div id="refresh-div" class="timedisplay">{% include 'booking/time.html' %}</div>
<div class="col-lg-1 md-hidden"></div>
</div>
</div>
sub page html:
<div class = "col-lg-6">
<h3 class = "h3-hour">2. Choose hour</h3>
<div class="row row-pad-20">
{% for time_list in availability_table %}
<div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
{% for i in time_list %}
<button type="submit" class="fade-in-quick btn btn-lg btn-block btn-info btn-core" value="{{ forloop.counter0 }}" name="time" id="time">{{ i.0|date:'H:i' }} do {{ i.1|date:'H:i' }}</button>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
main page script:
$('#datepicker div').datepicker({
language:"pl",
startDate: "+1d"
}).on('changeDate', function(event) {
var date = event.format()
console.log(date);
$.ajax({
type:'POST',
url: '/check/',
data: {'date': date, 'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val()},
success: function(data) {
$('#refresh-div').html(data);
}
});
});
Any idea why it doesn't work?
So apparently this div:
<div class="col-lg-4 col-md-12 col-sm-12 col-xs-12"></div>
Was causing problems. When i just deleted all classes after col-lg-4(they are not necessary anyway) everything is working correctly.