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.
Related
I am working on an application that has a page with a table that is a list of users. Each user has a button which pops up a modal that does something. I am trying to create the modal that will get the user information when the button in clicked, additionally, I need in that modal some logic based on the user information and some more data. I am thinking that it makes sense to create a separate view for it but since each view must be on a different url, the concept of the modal does not makes sense (for me), because I want it to be on the same url.
Is it possible to have a modal with a different view that will have a separate logic? Since the modal is included in the template and it is basically just one template, then, can one template have 2 views?
What is the best way to implement the modal using django? And how to pass data to it, I need the data from the row that was selected + some more data from db. I have the data from the context but manipulating that using JQuery for me is a bad idea - because I am using a python session on the backend that communicates with another api, so when user clickes the modal save button, a python request needs to be done, this means I need a view for it.
Here is my try
Modal
{% block modal %}
{% load static %}
{% load authorization_tags %}
<!-- Modal -->
<div class="modal fade" id="{{modal_id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="row">
<div class="col-lg-5">
<img class="d-block w-100"
src="{% static 'app/assets/images/security-shield1.png' %}"
alt="First slide">
Use access control to deauthorize user
</div>
<div class="col-lg-7">
<h2 class="h2-responsive product-name">
<strong>{{user.real_name}}</strong>
</h2>
<h4 class="h4-responsive">
<span class="green-text">
{{user.username}}
</span>
</span>
</h4>
<div class="accordion md-accordion" id="accordion1" role="tablist" aria-multiselectable="true">
<div class="card">
<div class="card-header" role="tab" id="heading2">
<a data-toggle="collapse" data-parent="#accordion1" href="#collapse1" aria-expanded="true"
aria-controls="collapse1">
<h5 class="mb-0">
Current Authorizations <i class="fas fa-angle-down rotate-icon"></i>
</h5>
</a>
</div>
<div id="collapse1" class="collapse show" role="tabpanel" aria-labelledby="heading1"
data-parent="#accordion1">
<div class="card-body">
{% for right in people_rights|user_active_rights:user.id %}
{{right.room}}
{% endfor %}
</div>
</div>
</div>
</div>
<div class="accordion md-accordion" id="accordion2" role="tablist" aria-multiselectable="true">
<div class="card">
<div class="card-header" role="tab" id="heading2">
<a data-toggle="collapse" data-parent="#accordion2" href="#collapse2" aria-expanded="true"
aria-controls="collapse2">
<h5 class="mb-0">
Available Authorizations <i class="fas fa-angle-down rotate-icon"></i>
</h5>
</a>
</div>
<div id="collapse2" class="collapse show" role="tabpanel" aria-labelledby="heading2"
data-parent="#accordion2">
<div class="card-body">
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="text-center">
<button type="button" class="btn btn-lg" data-dismiss="modal"><span>Close</span></button>
<button class="btn btn-lg"><span>Authorize</span></button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock modal %}
a piece of table and the modal included in the same template
{% include 'app/admin/users/user_authorize.html' with modal_id="authModal" user=row areas=areas rooms=rooms people_rights=people_rights %}
{%if row.empno %}
<td class="txt-oflo">{{ row.empno }}</td>
{% else %}
<td class="txt-oflo">-</td>
{% endif %}
<td>
{% with "#"|add:row.id as buttonId %}
<button id={{buttonId}} class="btn btn-lg" data-toggle="modal" data-target="#authModal">
<span>Authorize</span>
</button>
{% endwith %}
</td>
</tr>
You can try the following steps to solve the issue.
Create a separate view for the modal on a separate url.
Take the modal data out of this html file and place it in another html file. The empty modal in the original html should look something like this.
<div id="SampleTable" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">sample title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" id="sample_datatable">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
Render that new html from the new view that was created. The ajax request that will be activated from the button that gives us the modal table might look something like this.
#app.route('/sample_data', methods=['GET', 'POST'])
def modal_table():
try:
data = request.args.get('arg')
database_data = Table.query.filter(Table.data == data).all()
result_dict = [u.__dict__ for u in database_data]
except Exception as e:
traceback.print_exc()
return render_template('modal_table.html', data=enumerate(result_dict))
The button in the original html that results in the modal table should be configured in a way using ajax requests that it renders data from the new html into the old modal data like this.
function get_sample_data() {
$.ajax({
url:"/sample_data", //the page containing python script
type: "GET", //request type,
data: {},
async:true,
beforeSend: function(){
$('#sample_datatable').html('Loading..');
},
success:function(result){
$('#sample_datatable').html(result);
}
});
}
You can call this javascript function from the button that is supposed to show the modal table.
I have this HTML page in which I have 2 forms. Django is not checking the form validation for the first form. I want it to check form validation for the first form.
This is the Html Code
<form method="post" id="msform">
{% csrf_token %}
<!-- progressbar -->
<ul id="progressbar">
<li class="active" id="conf"><strong>Configuration</strong></li>
<li id="auth"><strong>Authentication</strong></li>
</ul>
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuemin="0" aria-valuemax="100"></div>
</div> <br> <!-- fieldsets -->
<fieldset>
<div class="form-card">
<div class="row">
<div class="col-7">
<h2 class="fs-title">Cluster Configuration</h2>
</div>
<div class="col-5">
<h2 class="steps">Step 1 - 2</h2>
</div>
</div>
{{ form1|crispy }}
</div> <input type="button" name="next" class="next action-button" value="Next" />
</fieldset>
<fieldset>
<div class="form-card">
<div class="row">
<div class="col-7">
<h2 class="fs-title">Authentication</h2>
</div>
<div class="col-5">
<h2 class="steps">Step 2 - 2</h2>
</div>
</div>
{{ form2|crispy }}
</div><button type="submit" class="btn btn-primary" >Next</button>
</fieldset>
</form>
If I use submit button instead of next for the first form then neither the second form opens nor the form is submitted (i.e. nothing is happening).
So I think the issue might be because you have over arching form tag, and two forms sent inside it from your view function:
What you have right now is this:
<form>
<fieldset>
<! –– Your Code ––>
{{ form1|crispy }}
</div> <input type="button" name="next" class="next action-button" value="Next" />
</fieldset>
<fieldset>
<! –– Your Code ––>
{{ form2|crispy }}
</div><button type="submit" class="btn btn-primary" >Next</button>
</fieldset>
</form>
As you can see from the above simplification of your original post, you have two forms templated inside one form tag. Thus when you hit either of the the submit button both of them gets sent.
If I am not mistaken, I believe what you might want is something along the lines of this:
<form name="form1" id="form1">
<fieldset>
<! –– Your Code ––>
{{ form1|crispy }}
</div> <input type="button" name="form1" class="next action-button" value="Next1" />
</fieldset>
</form>
<form name="form2" id="form2">
<fieldset>
<! –– Your Code ––>
{{ form1|crispy }}
</div> <input type="button" name="form2" class="next action-button" value="Next2" />
</fieldset>
</form>
Take note of the fact that I have changed your button names, as well as added ids and names to each form, you might also want to add ids as well as unique values to your buttons as well. This would help you build if conditions to determine which form has been submitted and so on, in your view function
Here is a link that describe how to handle this in more depth.
Which is all nice and dandy, but the conclusion of that linked page is this:
Let me know if it helps, feel free to ask more if you do not understand/the changes does not work
This is some code from my index.html. My issue is that the action on the form in the modal is not working (no error, just doing nothing) yet the form outside the model is working fine (commented test button). The model is opening fine and seems correctly formatted, yet the 'yes' button does nothing but closes the modal. The problem does not seem to be in the URL. Any help would be much appreciated. I am using django by the way
{% for patient in all_patients %}
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-body">
<!-- Name -->
<h4>{{ patient }}</h4>
<!-- View Details -->
View Details
<!-- Edit Details -->
Edit Details
<!-- Delete Patient -->
<input type="hidden" name="patient_id" value="{{ patient.id }}" />
<button type="submit" class="btn btn-default btn-sm" data-toggle="modal" data-target="#patient_id">
<span class="glyphicon glyphicon-trash"></span>
</button>
<!-- Modal -->
<div class="modal fade" id="patient_id" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Confirm delete</h4>
</div>
<div class="modal-body">
<p>Are you sure you want to delete {{ patient }}?</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-default" data-dismiss="modal">No</button>
<form action="{% url 'patients:patient-delete' patient.id %}" method="post" style="display: inline;">
{% csrf_token %}
<button type="submit" class="btn btn-danger" data-dismiss="modal">Yes</button>
</form>
</div>
</div>
</div>
</div>
<!-- test button -->
<form action="{% url 'patients:patient-delete' patient.id %}" method="post" style="display: inline;">
{% csrf_token %}
<button type="submit" class="btn btn-danger" data-dismiss="modal">Delete</button>
</form>
</div>
</div>
</div>
{% cycle '' '' '' '' '' '<div class="clearfix visible-lg"></div>' %}
{% endfor %}
I have a comments section on some pages on my site that I build with a {% for ... %} loop (and another nested loop for comment replies. The section was hacked together, and I am still learning web development and Django, so please forgive any frustrating sloppiness or weirdness. I am not concerned with efficiency at the moment, only efficacy, and right now it is not working quite right.
For each comment I have a Bootstrap dropdown button that will bring up the options Edit and Delete. Edit will open a modal to edit the comment. The modals are rendered with an {% include %} tag. Below I have included part of my code unmodified, rather than trying to simplify my example and risk leaving something crucial out:
<div class="panel panel-default">
{% for comment in spot.ordered_comments %}
<div class="panel-heading row">
<div class="col-sm-10">
<strong>{{ comment.poster.username }}</strong>
<em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
</div>
<div class="btn-group col-sm-2" role="group">
{% if comment.poster == user %}
<form id="delete-comment-form" class="form"
method="post" action="{% url 'delete_comment' spot.id comment.id %}">
{% csrf_token %}
</form>
{% include 'topspots/editmodal.html' with edit_type='comment' %}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-edit"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>Edit</li>
<li role="separator" class="divider"></li>
<li>
Delete
</li>
</ul>
</div>
{% endif %}
{% if user.is_authenticated %}
{% include 'topspots/replymodal.html' %}
<button type="button" class="btn btn-default" data-toggle="modal"
data-target="#replyModal">
Reply
</button>
{% endif %}
</div>
</div>
<div class="panel-body">
<div class ="row">
<div class="col-sm-8">
{{ comment.comment_text }}
</div>
</div>
<br/>
<!-- Comment replies -->
{% if comment.commentreply_set %}
{% for reply in comment.commentreply_set.all %}
<div class="row" style="padding-left: 1em">
<div class="col-sm-8 well">
<p>{{ reply.reply_text }}</p>
<div class="row">
<div class="col-sm-4">
<p>
<strong>{{ reply.poster.username }}</strong>
<em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
</p>
</div>
{% if reply.poster == user %}
{% include 'topspots/editmodal.html' with edit_type='reply' %}
<form id="delete-reply-form" class="form"
method="post" action="{% url 'delete_reply' spot.id reply.id %}">
{% csrf_token %}
</form>
<div class="col-sm-2">
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-edit"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-toggle="modal"
data-target="#editModal">Edit</a></li>
<li role="separator" class="divider"></li>
<li>
<a href="javascript:;"
onclick="$('#delete-reply-form').submit();">Delete</a>
</li>
</ul>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
Here is the edit modal:
<!-- editmodal.html -->
{% load static %}
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h2 class="modal-title" id="editModalLabel">
Edit {{ edit_type }}:
</h2>
</div>
<form action="{% url 'edit_comment' spot.id comment.id %}" method="post">
<div class="modal-body">
<input class="form-control" name="text" value="{{ comment.comment_text }}" autofocus>
<input type="hidden" name="edit_type" value="{{ edit_type }}">
{% csrf_token %}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-default">Finish editing</button>
</div>
</form>
</div>
</div>
</div>
<script>
$('.modal').on('shown.bs.modal', function() {
$(this).find('[autofocus]').focus();
});
</script>
and the reply modal:
<!-- replymodal.html -->
{% load static %}
<div class="modal fade" id="replyModal" tabindex="-1" role="dialog" aria-labelledby="replyModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h2 class="modal-title" id="replyModaLabel">
Reply to <strong>{{ comment.poster.username }}'s</strong> comment
</h2>
</div>
<div class="modal-body">
<form action="{% url 'reply_comment' spot.id comment.id %}" method="post">
<input class="form-control" name="reply_text" placeholder="Write a reply..." autofocus>
{% csrf_token %}
</form>
</div>
</div>
</div>
</div>
<script>
$('.modal').on('shown.bs.modal', function() {
$(this).find('[autofocus]').focus();
});
</script>
The issue I am having is that my reply and edit modals (e.g. {% include 'topspots/editmodal.html' with edit_type='reply' %} or {% include 'topspots/replymodal.html' %} seem to be only rendered once with the context of the first iteration of my for loop. So even though all the questions are correctly rendered on the page, when I click reply, edit or delete, regardless of which button I click (i.e., whether I click the button for the first comment, or the fifth comment, etc.) I can only reply to, edit, or delete the very first comment. I have a feeling that this has something to do with closures and scope in a way I am not quite understanding (I have gotten into trouble in the past with unexpected results using lambda in Python loops because of this or this), but I am not sure.
I did a test with the following view:
def test(request):
spots = Spot.objects.all()
return render(request, 'test.html', {'spots': spots})
and templates:
<!-- test.html -->
<h1>Hello world</h1>
{% for spot in spots %}
{% include 'testinclude.html' %}
{% endfor %}
and
<!-- testinclude.html -->
<h3>{{ spot.name }}</h3>
And it printed out a list of unique spot names, so why the difference with the modals?
As emulbreh postulates, a modal is in fact rendered for every comment. However, all of the modals have the same ID, so regardless of which comment’s edit button was clicked, the first modal gets triggered every time. IDs are supposed to be unique across an HTML document.
How can you fix this? You can make the IDs of the modals unique to each comment. You can get a unique identifier by writing id="editModal-{{ comment.id }}" or just id="editModal-{{ forloop.counter }} (documentation here).
But then your editModal.html template is coupled very tightly with your ‘master’ template. A better solution would be to use classes instead of IDs and put the identification where it belongs: the container of each comment. You can try:
adding an ID to each comment’s container:
<div class="panel panel-default">
{% for comment in spot.ordered_comments %}
<div class="panel-heading row" id="comment-{{ comment.id }}">
...
using classes instead of IDs in your modal templates as so:
<!-- editmodal.html -->
{% load static %}
<div class="modal fade editModal" tabindex="-1" ...>
...
changing data-target in your buttons from:
<li>Edit</li>
to:
<li>Edit</li>
It looks like all your edit modals will have the same id id="editModal" as well as your reply modals id="replyModal" if you are showing them based on id probably you will always open the first DOM element with that id. You could try appending a unique identifier like forloop.counter
https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#for
In my Django template, {{ form.ietf_tag|bootstrap }} renders as
Django rendering
<div class="form-group">
<label class="control-label " for="id_ietf_tag">IETF tag</label>
<div class=" ">
<input class=" form-control" id="id_ietf_tag" maxlength="12" name="ietf_tag" type="text">
</div>
</div>
I want to insert a <button> before <input>, so I figured I'll just copy, paste, and modify the rendered HTML to where it looks something like this:
Manual rendering
<div class="row">
<div class="col-md-6">
<form action="" method="post">
{% csrf_token %}
<!-- Manually render ietf_tag input -->
<div class="form-group flex {% if form.ietf_tag.errors %}has-error{% endif %}">
<label for="{{ form.ietf_tag.id_for_label }}" class="control-label">{{ form.ietf_tag.label }}</label>
<div class=" ">
<button class="btn btn-primary get-code" data-url="{% url 'ajax_temporary_code' %}">Get Code</button>
<input id="{{ form.ietf_tag.id_for_label }}" class="form-control temp-code required" maxlength="12" name="{{ form.ietf_tag.html_name }}1" type="text" disabled value="{{ form.ietf_tag.value|default:"-" }}">
</div>
<span class="help-block">{{ form.ietf_tag.errors.0 }}</span>
</div>
<!-- -->
{{ form.common_name|bootstrap }}
{{ form.native_name|bootstrap }}
{{ form.direction|bootstrap }}
{{ form.comment|bootstrap }}
<button type="submit" class="btn btn-primary pull-right">Create</button>
</form>
</div>
</div>
The problem
On <form> submission, everything else is submitted except the ietf_tag, which I manually rendered.
QueryDict: {u'common_name': [u''], u'comment': [u''], u'csrfmiddlewaretoken': [u'G6UP5DxrSHHPPQzj6SbxM06Hh8yT9ksm'], u'direction': [u'l'], u'native_name': [u'']}
I double check the name attribute and it was correct. There was no problem using Django-rendered input.
Why is this happening?
Maybe I can accomplish the same result without having to copy, paste, and modify the HTML directly in the template?
EDIT: Put more context in the HTML code
Silly me. The disabled attribute in <input> is what causes the problem. I removed it and now the value is included in the form submission.
Lesson learned
If your <input> is disabled, the value won't be submitted by the form.