I have a forms with submit , each form is to delete an object :
{% for person in persons %}
<form id='form' name='delete' action="{% url 'delete_person' person.id %}"
method='POST'>
{% csrf_token %}
<button type='submit' onclick="bootbox.confirm();" id="del" class='btn btn-xs btn-link icon'><i class='glyphicon glyphicon-remove'></i></button>
</form>
{% endfor %}
when i click on the remove icon the corresponding person should be removed ,
I'm using bootbox.confirm() :
<script type="text/javascript">
$(document).ready(function(){
$(".btn#del").click(function(e) {
e.preventDefault();
var lHref = $('form#form1').attr('action');
bootbox.confirm("Are you sure?", function(confirmed) {
if(confirmed) {
window.location.href = lHref;
}
});
});
})
</script>
I'm getting the url of the form like below :
var lHref = $('form#form1').attr('action');
bootbox.confirm("Are you sure?", function(confirmed) {
if(confirmed) {
window.location.href = lHref; ...
the issue is that the first user in the form gets deleted regardless of which delete button I click, so I'm wondering how can I pass $(this) to bootbox.confirm() so I can get the right URL
instead of binding to id of button(which is multiple in your case so it will bind only first button's event) use form's submit event
also remove the onclick from you button
{% for person in persons %}
<form id='form' name='delete' action="{% url 'delete_person' person.id %}"
method='POST'>
{% csrf_token %}
<button type='submit' id="del" class='btn btn-xs btn-link icon'><i class='glyphicon glyphicon-remove'></i></button>
</form>
{% endfor %}
in javascript
<script type="text/javascript">
$(document).ready(function(){
$("form").submit(function(e) {
e.preventDefault();
var lHref = $(this).attr('action');
bootbox.confirm("Are you sure?", function(confirmed) {
if(confirmed) {
window.location.href = lHref;
}
});
});
})
</script>
Related
Hi there I am fairly new to django and need to add dynamic formsets with autocomplete functions for every from. I am not entirely sure what I am doing wrong i have tried a few approaches and this is my most recent!
I have function called AutoproductComplete which receives the id of the current formset form input that i want to add the auto complete to. It doesnt work, no errors, not sure why. I also did it after the after method so assume the form has been added to the DOM?'
'html'
<form class="form-horizontal" method="POST" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="row form-row spacer">
<div class="input-group" style="padding:5px;">
{{form.productName}}
{{form.orderQuantity}}
<div class="input-group-append">
<button class="btn btn-success add-form-row"
style="margin:5px;">+</button>
</div>
</div>
</div>
{% endfor %}
<br>
<div class="row spacer">
<div class="col-12 offset-9">
<button type="submit" class="btn btn-block btn-
dark">Create Order</button>
</div>
</div>
</form>
JavaScript
'''
function AutoproductComplete(id){
const products = [];
console.log("This is working")
console.log(id)
{% for instance in products %}
products.push("{{instance.product_name}}")
{% endfor %}
$(id).autocomplete({
classes: {"ui-autocomplete-input": "highlight"},
source: products,
minLength: 1,
});
};
AutoproductComplete("id_form-0-productName" )
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var id = ""
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
`enter code here`newElement.find(
':input:not([type=button]):not([type=submit]):not([type=reset])')
.each(function() {
if ($(this).attr('name')){
var name = $(this).attr('name').replace('-' + (total-1) + '-', '-
' + total + '-');
id = 'id_' + name;
$(this).attr({'name': name, 'id':
id}).val('').removeAttr('checked');
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('<span class="glyphicon glyphicon-minus" aria-hidden="true" > -
</span>')
AutoproductComplete(id)
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
'''
You can use DAL
django-autocomplete-light
As it says, its quite lightweight and IMHO easily and highly configurable.
You can find the docs here:
https://django-autocomplete-light.readthedocs.io/en/master/
I'm trying to avoid inline javascript and would like to convert it to Alpine.js code. Is there a way to rewrite the following piece of code in Alpine.js?
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function () {
const message = "Do you really want to remove the selected e-mail address?";
const actions = document.getElementsByName('action_remove');
if (actions.length) {
actions[0].addEventListener("click", function (e) {
if (!confirm(message)) {
e.preventDefault();
}
});
}
});
document.addEventListener('DOMContentLoaded', function () {
$('.form-group').removeClass('row');
})
</script>
Here is the full context (I'm working with Django templates):
{% extends "account/base.html" %}
{% load tailwind_filters %}
{% load crispy_forms_tags %}
{% block head_title %}
Account
{% endblock %}
{% block inner %}
<h1>E-mail Addresses</h1>
{% if user.emailaddress_set.all %}
<p>The following e-mail addresses are associated with your account:</p>
<form action="{% url 'account_email' %}" class="email_list" method="post">
{% csrf_token %}
<fieldset class="blockLabels">
{% for emailaddress in user.emailaddress_set.all %}
<div class="radio">
<label for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}">
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary or user.emailaddress_set.count == 1 %}checked="checked" {%endif %} value="{{emailaddress.email}}" />
{{ emailaddress.email }}
{% if emailaddress.verified %}
<span class="verified">Verified</span>
{% else %}
<span class="unverified">Unverified</span>
{% endif %}
{% if emailaddress.primary %}<span class="primary">Primary</span>
{% endif %}
</label>
</div>
{% endfor %}
<div class="form-group">
<button class="secondaryAction btn btn-primary" type="submit" name="action_primary">Make Primary</button>
<button class="secondaryAction btn btn-primary" type="submit" name="action_send">Re-send Verification</button>
<button class="primaryAction btn btn-primary" type="submit" name="action_remove">Remove</button>
</div>
</fieldset>
</form>
{% else %}
<p><strong>Sad news:</strong>You currently do not have any e-mail address set up. You should add an e-mail address so you can receive notifications, reset your password, etc.</p>
{% endif %}
<h2>Add E-mail Address</h2>
<form method="post" action="{% url 'account_email' %}" class="add_email">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" name="action_add" type="submit">
Add E-mail
</button>
</form>
{% endblock %}
{% block inline_javascript %}
{{ block.super }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function () {
const message = "Do you really want to remove the selected e-mail address?";
const actions = document.getElementsByName('action_remove');
if (actions.length) {
actions[0].addEventListener("click", function (e) {
if (!confirm(message)) {
e.preventDefault();
}
});
}
});
document.addEventListener('DOMContentLoaded', function () {
$('.form-group').removeClass('row');
})
</script>
{% endblock %}
You can try something like this:
Initialize the parent form element with x-data and set the state variable confirmMsg to null.
On form submit you prevent the actual submit with #submit.prevent and check whether a confirm message (confirmMsg) was set. If yes, you prompt the user to confirm the set message. If the users confirms, you reset the confirmMsg to null and submit the form with $el.submit().
On the buttons, you can just set the respective confirmMsg with #click = "confirmMsg = 'Are you sure?'".
Here is a code example:
<script src="//unpkg.com/alpinejs" defer></script>
<form
x-data="{confirmMsg: null}"
#submit.prevent="
if (confirmMsg && !confirm(confirmMsg)) return;
confirmMsg = null;
alert('Submitting form...'); $el.submit()"
>
<button
#click="confirmMsg = 'Do you really want to remove the selected e-mail address?'"
type="submit"
name="action_remove"
>
Remove
</button>
</form>
I am trying to create a like button for my page. thats okey its working but when I click the button page is refreshing. When I click on the like button, I want the counter showing the number of likes to increase. I try used Ajax but I failed. here are my codes..
Views:
def liked_post(request,pk):
post =get_object_or_404(UserPosts, id=request.POST.get("userposts_id"))
liked = False
if post.like_post.filter(id = request.user.id).exists():
post.like_post.remove(request.user)
liked = False
else:
post.like_post.add(request.user)
liked = True
return HttpResponseRedirect(reverse('detail', args=[str(pk)] ))
def detail_post(request,_detail):
postDetail = UserPosts.objects.get(pk = _detail)
liked = False
if postDetail.like_post.filter(id= request.user.id).exists():
liked = True
context= {
"detail":postDetail,
"liked":liked
}
return render(request,"DetailPost.html",context)
Javascript file:
$(document).ready(function () {
//like ajax call
$('.like-form').submit(function (e) {
e.preventDefault();
const userposts_id = $('.like-btn').val();
const token = $('input[name=csrfmiddlewaretoken]').val();
const url = $(this).attr('action')
$.ajax({
method: "POST",
url: url,
headers: { 'X-CSRFToken': token },
data: {
'userposts_id': userposts_id
}
})
})
})
Template:
<form class="btn-group mt-1 like-form" action="{% url 'like_post' detail.pk %}"
method="POST">
{% csrf_token %}
{% if request.user.is_authenticated %}
{% if detail.username_id == request.user.id %}
<button class="btn btn-primary btn-sm" disabled>Like</button>
{% else %}
{% if liked %}
<button class="btn btn-danger btn-sm " type="submit" name="userposts_id"
value="{{ detail.id }}">Unlike</button>
{% else %}
<button class="btn btn-primary btn-sm like-btn"
type="submit" name="userposts_id" value="{{ detail.id }}">Like</button>
{% endif %}
{% endif %}
{% else %}
<span class="px-2 pt-1">
Login to like
</span>
{% endif %}
<span class="bg-dark px-4 pt-1 like-count text-white"> {{total_post_likes}}</span>
</form>
Does anyone have an idea?
You are redirecting to detail page in your like_post view. Instead of redirecting return JsonResponse
def liked_post(request):
if request.is_ajax():
pk = request.POST.get('userposts_id')
post = get_object_or_404(UserPosts,id=pk)
if request.user in post.like_post.all():
liked = False
post.like_post.remove(request.user)
else:
liked = True
post.liked.add(request.user)
return JsonResponse({'liked': liked, 'count': post.like_post.count()})
return redirect('detail')
this will return a json with liked and count .
<span class="bg-dark px-4 pt-1 like-count text-white"> {{total_post_likes}}</span>
Get span to render likes from js
$.ajax({
type: "GET",
url: url,
success: function (response) {
console.log(response) //response will be what you send in jsonresponse in django view
$('.like-count').innerHtml =`${response.count}`
}
})
I have a lot of forms on the page and when one of them is submitted I want to send request via ajax to the view and have an id of the article and other info. So I need to check if form that has been clicked is the same as event.target. I did something like this but don't know if it is correct(first console.log works but second not):
<div id = "list">
{% for article in news %}
<h1>{{ article.title }}</h1>
<p>{{ article.published }}</p>
<img src = "{{ article.url }}">
<p>
<button>Upvote</button>
<button>Downvote</button>
</p>
<div id="span">
{% with article.upvotes.count as total_upvotes and article.downvotes.count as total_downvotes %}
<span upvote-id = "{{ article.id }}">{{ total_upvotes }}</span><span> upvote{{ total_votes|pluralize}}</span>
<span downvote-id = "{{ article.id }}">{{ total_downvotes }}</span><span> downvote{{ total_votes|pluralize}}</span>
{% endwith %}
</div>
<form method = 'post' action = '{% url "news:news_list" %}' form-id = '{{ article.id }}' class="form">
{{ form.as_p }}
{% csrf_token %}
<input type = "submit" value = "post">
</form>
{% endfor %}
</div>
{% endblock %}
{% block domready %}
const
list = document.getElementById('list'),
items = document.getElementsByClassName('vote');
forms = document.getElementsByClassName('form');
list.addEventListener('click', voteFunc);
list.addEventListener('submit', commentFunc);
function commentFunc(event){
event.preventDefault();
const clickedForm = event.target;
console.log('event triggered');
for (let form in forms){
if (form == clickedForm){
console.log('form is event.target')
$.ajax({
url: '{% url "news:news_list" %}',
type: 'POST',
data: {'id':$(event.target).attr('form-id'), 'title':$(this).elemets['title_field'].text(), 'body':$(this).elemets['body_field'].text()},
dataType: 'json'
})
}
}
}
Hope to hear advice how to implement it better and what event.target contains
You can write event handler for form submit event .So, whenever submit button(post) is clicked this event will get called then use .serialize() method to get all inputs inside your form and also attach form-id using &name=value and then you can pass same to backend.
Demo Code :
//when form will get submit
$("form.form").submit(function(e) {
//serialize will get all inputs as name=value separted wth `& `
console.log("data to send --> " + $(this).serialize() + "&id=" + $(this).attr('form-id'))
$.ajax({
type: "POST",
url: '{% url "news:news_list" %}',
data: $(this).serialize() + "&id=" + $(this).attr('form-id'), //send same
dataType: 'json'
});
e.preventDefault();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="list">
<a href="{{ article.resource }}">
<h1>A1</h1>
</a>
<p>abcd..</p>
<img src="{{ article.url }}">
<p>
<button>Upvote</button>
<button>Downvote</button>
</p>
<div id="span">
<span upvote-id="1">23</span><span> 54</span>
<span downvote-id="1">2</span><span> 56</span>
</div>
<form method='post' action='{% url "news:news_list" %}' form-id='1' class="form">
<p><label>somehting:</label>
<input type="text" name="something"></p>
<input type="submit" value="post">
</form>
<a href="{{ article.resource }}">
<h1>A</h1>
</a>
<p>abcd..</p>
<img src="{{ article.url }}">
<p>
<button>Upvote</button>
<button>Downvote</button>
</p>
<div id="span">
<span upvote-id="2">23</span><span> 54</span>
<span downvote-id="2">2</span><span> 56</span>
</div>
<form method='post' action='{% url "news:news_list" %}' form-id='2' class="form">
<p><label>somehting:</label>
<input type="text" name="something"></p>
<input type="submit" value="post">
</form>
</div>
I am building a page in a Django project which has multiple comments each of which can be liked/unliked with a button next to the text. So the page has multiple like/unlike buttons.
The buttons display fine when the page is loaded, and I can use Ajax to send data to Django and update my database which works fine, and I can return data back to the Ajax success function.
What I can't work out is - how can I update the status of the actual button which was clicked. I am able to update the status of all of the buttons together on the page as per the code below (pointless I know!), but can't see how I reference the clicked button. I've tried passing and then returning the button id which I can display in an alert, but not sure if this is what I should be using or where I go from here?
HTML Template
{% for comments in comments_page %}
<p>
<b>{{ comments.created_at }} ({{ comments.user_type }})</b>
{% if comments.comment_liked is False %}
<button class="comment btn btn-primary btn-xs"
id={{ forloop.counter0 }}
data-surveyid="{{ comments.id }}"
data-commentliked="True"
type="button">
<span class="glyphicon glyphicon-star-empty"></span>
</button>
{% else %}
<button class="comment btn btn-success btn-xs"
id={{ forloop.counter0 }}
data-surveyid="{{ comments.id }}"
data-commentliked="False"
type="button">
<span class="glyphicon glyphicon-star"></span>
</button>
{% endif %}
</p>
<p>{{ comments.comments }}</p>
<br>
{% endfor %}
Javascript / Ajax
{% block javascript %}
<script type="text/javascript">
$(function() {
$('.comment').click(function() {
var surveyid, commentliked, buttonid;
surveyid = $(this).attr('data-surveyid');
commentliked = $(this).attr('data-commentliked');
buttonid = $(this).attr('id');
$.ajax({
url: '/evaluations/validate_username/',
data: {
'surveyid': surveyid,
'commentliked': commentliked,
'buttonid': buttonid
},
dataType: 'json',
type: 'get',
success: function (data) {
alert(data.buttonid);
$(".comment").removeClass('comment btn btn-primary btn-xs').addClass('comment btn btn-success btn-xs');
}
});
});
});
</script>
{% endblock %}
Just target the clicked button in your success function:
{% block javascript %}
<script type="text/javascript">
$(function() {
$('.comment').click(function() {
// the button instance that was clicked
var clickedBtn = $(this);
var surveyid, commentliked, buttonid;
// also, you can use data-* to get the data attributes
// surveyid = clickedBtn.attr('data-surveyid');
// commentliked = clickedBtn.attr('data-commentliked');
surveyid = clickedBtn.data('surveyid');
commentliked = clickedBtn.data('commentliked');
buttonid = clickedBtn.attr('id');
$.ajax({
url: '/evaluations/validate_username/',
data: {
'surveyid': surveyid,
'commentliked': commentliked,
'buttonid': buttonid
},
dataType: 'json',
type: 'get',
success: function (data) {
alert(data.buttonid);
clickedBtn.removeClass('comment btn btn-primary btn-xs')
.addClass('comment btn btn-success btn-xs');
}
});
});
});
</script>
{% endblock %}