I am building a feature to add different services to the checkout in my Django template, but I don't know how to add the total price when selecting checkboxes.
I put a change event on each checkbox and to this and when I check one it is supposed to add the service and its price in the card.
The card :
<div class="col-4">
<h4 class="d-flex justify-content-between align-items-center mb-3">
<span class="text-muted">Votre commande</span>
</h4>
<ul class="list-group mb-3" id="panier">
<li class="list-group-item d-flex justify-content-between lh-condensed">
<div>
<h6 class="my-0">{{annonce.titre_logement}}</h6>
<small class="text-muted">{{annonce.categorie_logement}}</small>
</div>
<span class="text-muted">{{annonce.loyer_tc}} €</span>
</li>
</ul>
<li class="list-group-item d-flex justify-content-between">
<span>Total (€)</span>
<strong><span id="total"></span> €</strong>
</li>
</div>
The checkboxes and the script :
{% for categorie in categorie_service %}
{% for service in services %}
{% if service.categorie.value == categorie_service.nom %}
<div class="form-check">
<input class="form-check-input" type="checkbox" name="service" value="{{ service.nom }}" id="service{{ service.id }}">
<label class="form-check-label" for="service{{ service.id }}">
{{ service.nom }}
</label>
</div>
<script>
$(document).ready(function() {
$('#service{{ service.id }}').change(function() {
if(this.checked) {
var returnVal = "<li class='list-group-item d-flex justify-content-between lh-condensed'>\
<div>\
<h6 class='my-0'>{{service.nom}}</h6>\
</div>\
<span class='text-muted'>{{service.price}}€</span>\
</li>"
$('#panier').append(returnVal);
var total
total = {{annonce.loyer_tc}}
total = total + parseInt({{service.price}} || 0,10);
totalDiv = document.getElementById("total");
totalDiv.innerHTML = total;
}
});
});
</script>
{% endif %}
{% endfor %}
{% endfor %}
and here is my view if needed :
def detail_annonce(request, pk):
myObject = Annonce.objects.get(id=pk)
image = ImageLogement.objects.all()
categorie_service = myObject.categorie_service.all()
services = Services.objects.all()
context = {'annonce': myObject, 'myImages': image, 'categorie_service': categorie_service, 'services':services}
return render(request, 'annonce/search/annonce_result.html', context)
Related
I have this view.html with Django:
{% for item in cart %}
<div class="card rounded-3 mb-4">
<div class="card-body p-4">
<div class="row d-flex justify-content-between align-items-center">
<div class="col-md-2 col-lg-2 col-xl-2">
<img
src="{{ item.product.product_image.url }}"
class="img-fluid rounded-3" alt="Cotton T-shirt">
</div>
<div class="col-md-3 col-lg-3 col-xl-3">
<p class="lead fw-normal mb-2">{{ item.product.name }}</p>
<p><span class="text-muted">
{% if item.product.is_service %}
Service
{% else %}
Product
{% endif %}
</span> <span class="text-muted">
</div>
<div class="col-md-3 col-lg-2 col-xl-2 d-flex product_data">
<input type="hidden" value="{{ item.product_id }}" class="prod_id">
{% csrf_token %}
{% if item.product.is_service == False %}
{% if item.product.quantity >= item.product_quantity %}
<div class="container">
<div class="row">
<div class="col-lg-2">
<div class="input-group">
<span class="input-group-btn">
<button type="button"
class=" changeQuantity quantity-left-minus btn btn-primary btn-number"
data-type="minus">
<span class="glyphicon glyphicon-minus"></span>
</button>
</span>
<input type="number" id="quantity"
class=" align-items-center qty-input"
value="{{ item.product_quantity }}">
<span class="input-group-btn">
<button type="button"
class="changeQuantity quantity-right-plus btn btn-primary btn-number"
data-type="plus">
<span class="glyphicon glyphicon-plus"></span>
</button>
</span>
</div>
</div>
</div>
</div>
{% else %}
<h4>Out of Stock</h4>
{% endif %}
{% endif %}
</div>
<div class="col-md-3 col-lg-2 col-xl-2 offset-lg-1">
<h5 class="mb-0">$ {{ item.product.selling_price }}</h5>
</div>
<div class="col-md-1 col-lg-1 col-xl-1 text-center">
<button class="text-danger delete_cart_item">Remove</button>
</div>
</div>
</div>
</div>
{% endfor %}
And here is the jQuery code:
// change the quantity in the cart
$('.changeQuantity').click(function(e) {
e.preventDefault();
var product_id = $(this).closest('.product_data').find('.prod_id').val()
var product_qty = $(this).closest('.product_data').find('.qty-input').val()
var token = $('input[name=csrfmiddlewaretoken]').val()
$.ajax({
method: 'POST',
url: '/update_cart/',
data: {
'product_id': product_id,
'product_qty': product_qty == null ? 1 : product_qty,
csrfmiddlewaretoken: token
},
success: function(response) {
console.log(response.status)
alertify.success(response.status)
// $('.cart-data').load(location.href + " .cart-data")
}
})
});
//delete
// change the quantity in the cart
$('.delete_cart_item').click(function(e) {
e.preventDefault();
var product_id = $(this).closest('.product_data').find('.prod_id').val()
var token = $('input[name=csrfmiddlewaretoken]').val()
$.ajax({
method: 'POST',
url: '/delete_cart/',
data: {
'product_id': product_id,
csrfmiddlewaretoken: token
},
success: function(response) {
console.log(response.status)
alertify.success(response.status)
// $('.cart-data').load(location.href + " .cart-data")
}
})
})
in the first code for (changeQuantity) I could access the product_id... but with the second I couldn't it is just (undefined) ??? ..... but when change the second one to
var product_id = $('.prod_id').val()
I access it successfully...
my question is why? it is just a same file and code?
and is there a better way to work with those thinks in jquery
.product_data is an ancestor of .changeQuantity so you can use closest to go from .changeQuantity to .product_data but .product_data is not an ancestor of .delete_cart_item so you cant use closet to select it.
The parent div of .delete_cart_item is a sibling of .product_data so you can use the method below to get uoyr data.
var product_id = $(this).parent().prevAll('.product_data').find('.prod_id').val()
I work with Symfony and Twig. I currently have a twig page containing a list of products, I display them with a foreach loop and I put pagination to limit the display of products.
I have a form in this page with a checkbox as input and I need to keep my checkbox checked save in session when I go to the next page
I tried to do it with adding this code
there is some code, I added some comment in the pagination view and controller to explain what I tried.
view of my loop :
<form>
<div class="row" >
{% for annonce in annonces %}
<div class="col-12 col-md-6 col-lg-4">
<p class="text text--blue text--bold m-0 text--medium mt-2">
{{ annonce._source.titre }}
</p>
<p class="m-0">{{ 'Réf' }}: {{ annonce._source.reference }}</p>
<div class="d-flex mt-2 text--bold">
<div class="d-flex me-2">
{{ annonce._source.ville }}
</div>
</div>
<div>
<input type="checkbox" name="checkbox[]" id="checkbox_pdf" value="{{annonce._id}}" multiple/>
</div>
</div>
{% endfor %}
</div>
<input type="submit" id="pdf_submit" value="Create PDF" name="submit_pdf" class="btn btn-primary">
</form>
view of the pagination :
// I tried to add a onclick : onclick='document.forms["name"].submit(); return false;' on each pagination link combined with the save of the value in session with my controller but doesn't work
<div class="col d-flex justify-content-between align-items-center">
<div class="d-flex">
{% if page > 0 %}
<a href="#" data-action="pagination" data-uri="{{ path('ajax_annonce_pagination',{'page':0, 'type':'frontoffice'}) }}" data-target="pagination-target">
«
</a>
<a href="#" data-action="pagination" data-uri="{{ path('ajax_annonce_pagination',{'page':page-1, 'type':'frontoffice'}) }}" data-target="pagination-target">
{{ 'Précédent' }}
</a>
{% else %}
<a href="#" disabled="disabled" >
{{ 'Précédent' }}
</a>
{% endif %}
</div>
<div>
<ul class="list-unstyled pagination m-0">
{% for i in (page+1)..(page+4) %}
{% if i <= numberOfMaxPage %}
{% if i == (page+1) %}
<li>
<a href="#" data-action="pagination" data-uri="{{ path('ajax_annonce_pagination',{'page':(i-1), 'type':'frontoffice'}) }}" data-target="pagination-target">
{{ i }}
</a>
</li>
{% else %}
<li>
<a href="#" data-action="pagination" data-uri="{{ path('ajax_annonce_pagination',{'page':(i-1), 'type':'frontoffice'}) }}" data-target="pagination-target">
{{ i }}
</a>
</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
</div>
<div class="d-flex">
{% if page < (numberOfMaxPage-1) %}
<a href="#" data-action="pagination" data-uri="{{ path('ajax_annonce_pagination',{'page':page+1, 'type':'frontoffice'}) }}" data-target="pagination-target">
{{ 'Suivant' }}
</a>
<a href="#" data-action="pagination" data-uri="{{ path('ajax_annonce_pagination',{'page':numberOfMaxPage-1, 'type':'frontoffice'}) }}" data-target="pagination-target">
»
</a>
{% endif %}
</div>
</div>
JS of the pagination :
$( document ).ready(function() {
$(document).on('click', 'a.pagination',function(e) {
e.preventDefault();
$.ajax({
url: $(this).data('uri'),
}).done(function(html) {
$('#pagination-target').html(html);
$('html,body').animate({scrollTop: $('#pagination-target').offset().top - 80}, 200);
var $scrollable = document.getElementById('pagination-target');
$scrollable.scrollIntoView();
});
});
});
In my controller I render my view like this :
public function search(Request $request, ?SecteurGeographique $secteurGeographique, AnnonceRepository $annonceRepository): Response
{
$selectId = $request->get('checkbox');
$selected = $annonceRepository->findById($selectId);
// I tried to add this code to save my values
if (isset($selectId))
{
$session = new Session();
$session->set('checkbox',$selectId);
}else{
echo 'false';
$session = new Session();
$session->clear();
}
return $this->render('front/annonce/list.html.twig', array(
'annonces' => $results['hits']['hits'],
'total' => $results['hits']['total']['value'],
'website' => $website,
'page' => $request->query->getInt('page')
));
}
It is better to do a save in session my php or in ajax ?
thanks you in advance
Actually, if I understood correctly your code, you don't really need to use session.
I assume that, when you submit the form, then you will need to post all the checkbox value at once to generate your PDF.
If that is try, you should only store the list of the checkboxes directly via Javascript and be sure to send everything when you submit your form.
In this theory, there could be you HTML main page :
<form>
<div class="row" >
{% for annonce in annonces %}
<div class="col-12 col-md-6 col-lg-4">
<p class="text text--blue text--bold m-0 text--medium mt-2">{{ annonce._source.titre }}</p>
<p class="m-0">{{ 'Réf' }}: {{ annonce._source.reference }}</p>
<div class="d-flex mt-2 text--bold">
<div class="d-flex me-2">
{{ annonce._source.ville }}
</div>
</div>
<p>
<input type="checkbox" name="checkbox[]" class="checkboxPDF" value="{{annonce._id}}"/>
</div>
{% endfor %}
</div>
<div id="savedCheckboxes" class="d-none"></div>
<input type="submit" id="pdf_submit" value="Create PDF" name="submit_pdf" class="btn btn-primary">
</form>
Here, you can see that I added the invisible div #savedCheckboxes. That will allow us to save all the checkboxes when you change your pages. I also corrected a little bit your HTML, but nothing major.
Then you should update your pagination javascript :
$(document).ready(function() {
$(document).on('click', 'a.pagination',function(e) {
e.preventDefault();
// Save all the selected checkboxes by moving them to #savedCheckboxes
$('.checkboxPDF:checked').appendTo($('#savedCheckboxes'))
// Do your pagination like you did
$.ajax({
url: $(this).data('uri'),
}).done(function(html) {
$('#pagination-target').html(html);
// If the user come to a previous page, verify if he did selected a checkbox
$('#pagination-target .checkboxPDF').each(function(i, element) {
// If the checkbox already exists in the #savedCheckboxes, then select this checkBox & remove it from #savedCheckboxes
var savedCheckbox = $('#savedCheckboxes .checkboxPDF[value="'+element.val()+'"]')
if(savedCheckbox.length > 0) {
element.click() // Select this checkbox
savedCheckbox.remove() // Remove it from the hidden selection
}
})
$('html,body').animate({scrollTop: $('#pagination-target').offset().top - 80}, 200);
var $scrollable = document.getElementById('pagination-target');
$scrollable.scrollIntoView();
});
});
});
And the magic is done ... When you will submit your form, you will always receive ALL the list of the selected Checkbox, even those that are not displayed anymore because of your pagination.
Problem
I want to the following things but am unable to understand that how can I do the following things.
Firstly, I want that when the page is loaded the defualt values should be displayed from using the value from the combox. For example pack of 1KG is the defualt value so it's price and other values should be updated when the page is loaded.
Secondly, I want that when the product is added to the cart the page is not reloaded or refreshed and a popup is shown that the product is added to the cart.
CODE
Script
$(document).on("change", '.tranactionID', function (event) {
event.preventDefault();
//get closest outer div..
var selector = $(this).closest(".productID")
//find to get required elements..
selector.find('.id_price').text($(this).children(":selected").attr("price"));
selector.find('.price-sale').text($(this).children(":selected").attr("sale_price"));
selector.find('.id_discount').text($(this).children(":selected").attr("discount"));
let id = $(this).find("option:selected").attr('transID');
let Url = `{% url 'cart:cart_add' 0 %}`.replace(0, id);
selector.find("form").attr('action', Url);
});
HTML
{% regroup transaction by productID as ProductList %}
{% for productID in ProductList %}
<div class="col-sm-3 productID" >
<div class="product">
<a href="{% url 'main:product-detail' productID.grouper.id %}" class="img-prod"><img class="img-fluid" src={{productID.grouper.product_image.url}} alt="" height="200px">
<span class="status id_discount">%</span>
<div class="overlay"></div>
</a>
<div class="text py-3 pb-4 px-3 text-center">
<h3>{{productID.grouper}}</h3>
<div class="d-flex">
<div class="pricing">
<p class="price"><span class="mr-2 price-dc id_price">Rs. </span><span class="price-sale">Rs. </span></p>
</div>
</div>
<select class="tranactionID" id="ItemID" style="width: 250px;">
{% for val in productID.list %}
<option transID={{val.id}} price={{val.Price}} discount={{val.discount_percentage}} sale_price={{val.get_sale}} class="price_value" >{{val.AUID}} - {{val.Description}}</option>
{% endfor %}
</select>
<form id='transactionIDValue' class="d-inline" method="post">
{{cart_product_form}}
{% csrf_token %}
<input type="submit" id="Id_submit" class="btn btn-primary shadow px-5 py-2" value="Add To Cart">
<!-- <button type="submit" class="btn btn-primary shadow px-5 py-2">Add to Cart</button> -->
</form>
</div>
</div>
</div>
{% endfor %}
When the list-item-action class button is select or is active I want to appear a name in the skill_category input box and then send it to the models of my website.
This code is not giving a name of list-item.
It is returning an empty value in the skill_category input in my form:
$(document).ready(function() {
$('.list-group-item-action').click(function() {
if ($('.list-group-item-action').hasclass('active')) {
var cat_txt = "";
$('.list-group-item-action').each(function() {
cat_txt += $(this).val()
});
$('#cat_txt').val(txt);
}
});
});
<div class="row">
<div class="col-4">
<div class="list-group" id="list-tab" role="tablist">
<a class="list-group-item list-group-item-action active" id="list-lead_generator-list" data-toggle="list" href="#list-lead_generator" role="tab" aria-controls="lead_generator" value="Lead generator"><i class='fas fa-users'></i>Lead generator</a>
<a class="list-group-item list-group-item-action" id="list-content_creator-list" data-toggle="list" href="#list-content_creator" role="tab" aria-controls="content_creator" value="Content Creator"><i class='fas fa-pen'></i>Content Creator</a>
<a class="list-group-item list-group-item-action" id="list-social-social_media_handler-list" data-toggle="list" href="#list-social_media_handler" role="tab" aria-controls="social_media_handler" value="Social Media Handler"><i class='fas fa-icons'></i>Social Media Handler</a>
</div>
</div>
<div class="col-8">
<div class="tab-content" id="nav-tabContent">
{% comment %} <input class="bg-white rounded border border-gray-400 focus:outline-none focus:border-indigo-500 text-base px-4 py-2 mb-4" placeholder="Skill" name="Skill" type="text"> {% endcomment %}
<div class="tab-pane fade show active" id="list-lead_generator" role="tabpanel" aria-labelledby="list-lead_generator-list">
<label class="container">Lead Generator
<input type="checkbox" name="lead_generator" value='Lead Generator' class="lead_generator">
<span class="checkmark"></span>
</label>
</div>
</div>
</div>
</div>
<form method="post">
{% csrf_token %}
<input type='text' name="user" class="user" value="{{user.username}}" />
<input type="text" name="skill_category" id="cat_txt" class="skill_category">
<input type="text" name="skill" id="txt" class="skill">
<div class='container nxtbtn'>
<button type="submit" class="btn btn-warning"> Next Page </button>
</div>
</form>
Here are my models.py
models.py
class Skill(models.Model):
user = models.CharField(max_length=50)
skill_category = models.CharField(max_length=50)
skill = models.CharField(max_length=500)
def __str__(self):
return self.user
and here is my views
views.py
def skillsSelect(request):
if request.method == 'POST':
saveskill = Skill()
saveskill.user = request.POST.get('user')
saveskill.skill_category = request.POST.get('skill_category')
saveskill.skill = request.POST.get('skill')
saveskill.save()
return render(request, 'growithkaizen/skillsSelect.html')
else:
return render(request, 'growithkaizen/skillsSelect.html')
javaScript
$(document).ready(function() {
$('.list-group-item').click(function() {
if ( $('.list-group-item').hasClass('active') ) {
$('#cat_txt').val($(this).attr('value'));
}
});
I have a dropdown and list of property. The dropdown contains two option, Low to High and High to Low. If any user clicks on any one of the dropdown item, the properties listed should sort by its price. How can I achieve that using javascript?
property.html
<div class="col-sm-6">
<div class="pxp-sort-form form-inline float-right">
<div class="form-group">
<select class="type-regular custom-select" id="pxp-sort-results" name="price-sorting">
<option value="" selected="selected disabled">Default Sort</option>
<option class="price-sorting" value="l2h" id="l2h">Price (Lo-Hi)</option>
<option class="price-sorting" value="h2l">Price (Hi-Lo)</option>
</select>
</div>
</div>
</div>
<div class="row products-grid">
{% for item in properties.all %}
<div class="col-sm-12 col-md-6 col-xxxl-4 product">
<a href="{% pageurl item %}" class="pxp-results-card-1 rounded-lg" data-price="{{ item.price }}" data-prop="1">
<div id="property-{{item.id}}" class="carousel slide" data-ride="carousel" data-interval="false">
<div class="carousel-inner">
{% for j in item.prop_images.all %}
{% image j.prop_img original as property_img %}
<div class="carousel-item {% if forloop.first %} active {% endif %}" style="background-image: url('{{property_img.url}}')"></div>
{% endfor %}
</div>
<span class="carousel-control-prev" data-href="#{{item.prop_name}}" data-slide="prev">
<span class="fa fa-angle-left" aria-hidden="true"></span>
</span>
<span class="carousel-control-next" data-href="#property-{{item.id}}" data-slide="next">
<span class="fa fa-angle-right" aria-hidden="true"></span>
</span>
</div>
<div class="pxp-results-card-1-gradient"></div>
<div class="pxp-results-card-1-details" id="prop-dtls">
<div class="pxp-results-card-1-details-title">{{item.prop_name}}</div>
<div class="pxp-results-card-1-details-price price">{{item.price}}</div>
</div>
<div class="pxp-results-card-1-features">
<span>{{item.bedroom}} BD <span>|</span> {{item.bathroom}} BA <span>|</span> {{item.sqft}} SF</span>
</div>
<div class="pxp-results-card-1-save"><span class="fa fa-star-o"></span></div>
</a>
</div>
{% endfor %}
</div>
The values are coming dynamically from backend.
You can either do this with Javascript (reordering the DOM elements) or with the response you get from your server.
JS:
function reverseChildren(parent) {
for (var i = 1; i < parent.childNodes.length; i++){
parent.insertBefore(parent.childNodes[i], parent.firstChild);
}
}
You can set add an onclick JS event handler on the parent DIV of the elements to reverse all the child elements.
Source: https://stackoverflow.com/a/37860657/3345051
OR
You can send a response back from the server using the .order_by() filter method with a flag in the request to determine if it is reverse or not.
For example:
Non-reverse - Item.objects.all().order_by('price')
Reversed - Item.objects.all().order_by('-price')
class ItemView(View):
def get(self, request, *args, **kwargs):
isReversed = '-price' if request.GET['reverse'] is True else 'price'
items = Item.objects.all().order_by(isReversed)
return JsonResponse(items)
The below code worked perfectly as I wanted.
$(document).on("change", ".price-sorting", function() {
var sortingMethod = $(this).val();
if(sortingMethod == 'l2h')
{
sortProductsPriceAscending();
}
else if(sortingMethod == 'h2l')
{
sortProductsPriceDescending();
}
});
function sortProductsPriceAscending()
{
var products = $('.product');
products.sort(function(a, b){
return $(a).data("price") - $(b).data("price")});
$(".products-grid").html(products);
}
function sortProductsPriceDescending()
{
var products = $('.product');
products.sort(function(a, b){ return $(b).data("price") - $(a).data("price")});
$(".products-grid").html(products);
}
HTML code
<div class="col-sm-6">
<div class="pxp-sort-form form-inline float-right">
<div class="form-group">
<select class="type-regular custom-select price-sorting" id="pxp-sort-results">
<option value="" selected="selected disabled">Default Sort</option>
<option value="l2h" id="l2h">Price (Lo-Hi)</option>
<option value="h2l">Price (Hi-Lo)</option>
</select>
</div>
<div class="form-group d-flex">
<a role="button" class="pxp-map-toggle"><span class="fa fa-map-o"></span></a>
</div>
</div>
</div>
<div class="row products-grid">
{% for item in properties.all %}
<div class="col-sm-12 col-md-6 col-xxxl-4 product" data-price="{{ item.price }}">
<a href="{% pageurl item %}" class="pxp-results-card-1 rounded-lg" data-prop="1">
<div id="property-{{item.id}}" class="carousel slide" data-ride="carousel" data-interval="false">
<div class="carousel-inner">
{% for j in item.prop_images.all %}
{% image j.prop_img original as property_img %}
<div class="carousel-item {% if forloop.first %} active {% endif %}" style="background-image: url('{{property_img.url}}')"></div>
{% endfor %}
</div>
<span class="carousel-control-prev" data-href="#{{item.prop_name}}" data-slide="prev">
<span class="fa fa-angle-left" aria-hidden="true"></span>
</span>
<span class="carousel-control-next" data-href="#property-{{item.id}}" data-slide="next">
<span class="fa fa-angle-right" aria-hidden="true"></span>
</span>
</div>
<div class="pxp-results-card-1-gradient"></div>
<div class="pxp-results-card-1-details" id="prop-dtls">
<div class="pxp-results-card-1-details-title">{{item.prop_name}}</div>
<div class="pxp-results-card-1-details-price price">₹ {{item.price}}</div>
</div>
<div class="pxp-results-card-1-features">
<span>{{item.bedroom}} BD <span>|</span> {{item.bathroom}} BA <span>|</span> {{item.sqft}} SF</span>
</div>
<div class="pxp-results-card-1-save"><span class="fa fa-star-o"></span></div>
</a>
</div>
{% endfor %}
</div>