Question:
How can I show the number of items in a user's cart using the minicart.js script?
Backstory:
I'm developing a static HTML website that is selling a small number of products using standard PayPal buttons and minicart.js
I'd like to have an area in the header of my website that displays the number of items currently in the "cart", but I can't figure out how to do so. There is no example detailing this functionality on the minicart.js website.
I'm sure it can be done, but I'm at a loss. Any help would be greatly appreciated. Thanks!
You can get like this:
paypal.minicart.cart.items().length
It works for me
I managed to figure out a way to achieve what I'm looking for by finding the necessary variable set through minicart.js and then manipulating it via jQuery.
minicart.js gives me the following variable which outputs the current cart total:
paypal.minicart.cart.total();
I then took that variable and applied some jQuery that converted this variable into a separate variable called "cartTotal" which is checked and updated every time a user interaction happens on the page (ie - a click or a keypress). I found that a brief delay was needed in order for everything to work properly. Interestingly, the keypress check needs a longer delay than the mouse click.
My final (for now) working code is as follows:
$( document ).ready(function() {
var cartTotal = paypal.minicart.cart.total();
$('input#cart').val('$' + cartTotal);
$( "body" ).click(function() {
setTimeout(function() { // Setting slight delay on function to accomodate for button push of removing items from cart
var cartTotal = paypal.minicart.cart.total();
$('input#cart').val('$' + cartTotal);
}, 100);
});
$( "body" ).keypress(function() {
setTimeout(function() { // Setting longer delay on function to accomodate for key push of removing items from cart
var cartTotal = paypal.minicart.cart.total();
$('input#cart').val('$' + cartTotal);
}, 900);
});
Related
I'm trying to hide the shipping calculator on my cart page (using jQuery) depending on which shipping method is selected, first on page load, and then when a user selects another method or updates the cart, that would enable / disable new shipping methods but I can't seem to make it work.
My Javascript / jQuery is pretty rusty so I don't know what I'm doing wrong.
The code bellow is what I've tried so far. It does work like I want on page load (= if "free shipping" is selected OR if it's the only available shipping method, the shipping calculator will be hidden.
But then when I choose another shipping method, the shipping calculator won't show up again unless I manually reload the page.
It won't work either if the cart is updated with extra product quantities (by increasing the amount of products directly on the cart page) to reach the minimum amount to have free shipping.
jQuery(document).ready(function() {
if(jQuery("*[id*=free_shipping]").is(':checked') || jQuery("*[id*=free_shipping]").is(':hidden') ){
jQuery(".woocommerce-shipping-calculator").css("display","none");
}
else{
jQuery(".woocommerce-shipping-calculator").css("display","block");
}
});
jQuery("input[type=radio]").click(function() {
if(jQuery("*[id*=free_shipping]").is(':checked')){
jQuery(".woocommerce-shipping-calculator").css("display","none !important");
}
else{
jQuery(".woocommerce-shipping-calculator").css("display","block !important");
}
})
Any help would be highly appreciated !
Thanks
thanks a lot for your explanation and code.
It almost works perfectly except when I try to update my cart. If I have a cart worth enough to trigger free shipping (over 150€) and then I remove a product to have a cart bellow 150€ and click "update cart", then regular shipping methods will show but the shipping calculator won't be displayed again.
To have it showing again I'll have to click on one of the shipping methods' radio button.
I've tried to tweek the code you gave me doing something like that but couldn't make it work :/
jQuery(document).ready(function($) {
if(jQuery("*[id*=free_shipping]").is(':checked') || jQuery("*[id*=free_shipping]").is(':hidden') ){
jQuery(".woocommerce-shipping-calculator").css("display","none");
}
else{
jQuery(".woocommerce-shipping-calculator").css("display","block");
}
jQuery('body').on('click', "input[type=radio]",function() {
if(jQuery("*[id*=free_shipping]").is(':checked') || jQuery("*[id*=free_shipping]").is(':hidden')){
setTimeout(function(){jQuery(".woocommerce-shipping-calculator").hide();}, 500);
}
else{
setTimeout(function(){jQuery(".woocommerce-shipping-calculator").show();}, 500);
}
});
});
jQuery("input[type=submit]").on('click', function() {
if(jQuery("*[id*=free_shipping]").is(':checked') || jQuery("*[id*=free_shipping]").is(':hidden')){
setTimeout(function(){jQuery(".woocommerce-shipping-calculator").hide();}, 500);
}
else{
setTimeout(function(){jQuery(".woocommerce-shipping-calculator").show();}, 500);
}
});
I've tried with ".button" instead of "input[type=submit]" and also tried to put this piece of extra code inside the whole jQuery(document).ready(function($) {[...]}).
Also I do have another question : hidding / showing the shipping calculator won't mess with inner WooCommerce functionning right ? Because I've posted on wordpress.org too and someone from Woo Support told me it was fairly complex development topic. So i'm wondering if I should not do it ?
Thanks again !
Try the following script, it will work. In fact, on each radio box selection, shipping selector was reloading and whenever you reload an HTML element so .click() event requires a new binding with that. In jQuery we used to call it .live() earlier and now we use .on(). It keeps the binding intact with the new reloaded element with the same selector or identity.
jQuery(document).ready(function($) {
if(jQuery("*[id*=free_shipping]").is(':checked') || jQuery("*[id*=free_shipping]").is(':hidden') ){
jQuery(".woocommerce-shipping-calculator").css("display","none");
}
else{
jQuery(".woocommerce-shipping-calculator").css("display","block");
}
jQuery('body').on('click', "input[type=radio]",function() {
if(jQuery("*[id*=free_shipping]").is(':checked')){
setTimeout(function(){jQuery(".woocommerce-shipping-calculator").hide();}, 500);
}
else{
setTimeout(function(){jQuery(".woocommerce-shipping-calculator").show();}, 500);
}
});
});
I have a page that displays a table with numbers. These are the prices my partner sees in the store. This page is specially made for him.
Prices change often. I enter prices in WordPress. I created Custom Post Type and a simple form to enter these numbers. One price = one custom field. The number of fields is around 30.
And it works great. But I need to detect the price change.
I would like the site for my partner clearly show the price change.
The ideal situation is when the DIV with new price has a changed color, and next to it appears a button to reset its color.
Such a mechanism will allow you to quickly find out about price changes.
This page is refreshed every 10 seconds.
I know the basics of JS, but I do not know how to do it. I suspect you will need to use SessionStorage.
Can anyone give me directions or paste a link to similar solution?
I have a lot of divs such as:
<div id="price1">[types field='price1'][/types]</div>
and JS:
setTimeout(function(){
window.location.reload(1);
}, 10000);
var price1 = document.getElementById('price1').textContent;
sessionStorage.setItem("price1-box", "price1");
var handle_storage = function () {
console.log('change in storage! new' + price1);
};
window.addEventListener("storage", handle_storage, false);
I made o solution. Maybe it will be useful to someone else.
<div id="eur-k">123</div>
window.onload = function() {
setTimeout(function(){
window.location.reload(1);
}, 30000);
// define div to add or remove alert
var eurkDiv = document.getElementById('eur-k');
// store current content in a variable
var eurk = eurkDiv.textContent;
// compare local storage with current content to make alarm
if (localStorage.getItem('eurkLoc') != eurk) {
eurkDiv.classList.add("active");
eurkDiv.innerHTML = eurk + "<button type=\"button\" class=\"potwierdzenie\" onclick=\"resetFunction()\">OK</button>";
}
function resetFunction() {
eurkDiv.classList.remove("active");
eurkDiv.textContent = eurk;
localStorage.setItem('eurkLoc', eurk);
};
};
Weird problem. I'm modifying shop template:
https://demo.themeisle.com/shop-isle/product-category/clothing/dresses/
At this moment when you hover product's picture there will show "add to cart" button. This is .
Under picture there is price
I prepared code:
var from = document.getElementsByClassName("woocommerce-Price-amount amount");
jQuery(document).ready(function(){
jQuery.each(from, function(i, el) {
jQuery(el.parentNode.parentNode).find(jQuery(".product-button-wrap")).append(el);
});
});
Nothing happens. This code work only if I set timeout:
setTimeout(function() {
var from = document.getElementsByClassName("woocommerce-Price-amount amount");
jQuery(document).ready(function(){
jQuery.each(from, function(i, el) {
jQuery(el.parentNode.parentNode).find(jQuery(".product-button-wrap")).append(el);
});
});
}, 10000);
Of course timeout it's not a solution. I was trying to find out minimal time to obtain best behavior but it's impossible. I have feeling that every browser (and version...) needs personalized time setting.
I thought that after 24-hour break I will get some brillant idea, but that doesn't work, no more ideas.
--- EDIT ---
OK, thanks for pointed mixed common js with jquery - I will correct that later.
jQuery(document).ready(function(){
var from = document.getElementsByClassName("woocommerce-Price-amount amount");
jQuery.each(from, function(i, el) {
jQuery(el.parentNode.parentNode).find(jQuery(".product-button-wrap")).append(el);
console.log(el);
});
});
That's logical that var from should be inside ready but this still doesn't work. No effect.
If I use in loop console.log it will return for me html code of el.
--- EDIT ---
Thanks. While testing I noticed something. I wanted append element .woocommerce-Price-amount.amount to element .product-button-wrap. But how can I do that if element .product-button-wrap isn't originally in source? This object is created dynamically (I don't know how).
-- EDIT --
OK. I checked JS files and found code adding to DOM .product-button-wrap so I putted my code there and now everything works. Thanks for help.
The problem is because you're running your code before the DOM has loaded. You need to retrieve the elements within the document.ready event handler.
Also note that you have an odd mix of native JS and jQuery methods. I'd suggest using one or the other, like this:
jQuery(function($) {
$('.woocommerce-Price-amount.amount').each(function() {
$(this).parent().parent().find('.product-button-wrap').append(this);
});
});
Also note that .parent().parent() should be replace by a single call to closest(), but I can't give you an exact example of that without seeing your HTML.
I have a page with a lot of elements (~1,500) of the same class on it, and when I execute
$(".pickrow").addClass("vis");
it takes a second or two for the page to reflect the changes. So that users aren't thinking the page was stuck, I'd like to pop-up a small message using:
$("#msgDiv").show();
$(".pickrow").addClass("vis");
$("#msgDiv").hide();
But the msgDiv never shows. If I remove the $("#msgDiv").hide(); the msgDiv appears simultaneously with the application of the added class (after the 1 or 2 seconds it took to add the class).
It seems like the jQuery functions get pooled and run together without any screen updates until they have all completed.
How can I get the msgDiv to appear while the $(".pickrow").addClass("vis"); is processing?
Here's a Demo
You probably want to delay the hide by a few seconds.
$("#msgDiv").show();
$(".pickrow").addClass("vis");
setTimeout(function(){ $("#msgDiv").hide(); },2000);
Or using jQuery's animations queue for timing:
$("#msgDiv").show();
$(".pickrow").addClass("vis");
$("#msgDiv").delay(2000).hide(1); //must make it at least 1 ms to go into the queue
You can go with this approach also
Working DEMO
$(document).on("click",".btn",function(){
$(".msg").show("fast",function(){
$(".pickrow").addClass("vis");
var interval = setInterval(function(){
var picLength = $(".pickrow").length;
var visLength = $(".vis").length;
if(picLength == visLength){
clearInterval(interval);
$(".msg").hide();
}
},500);
});
});
I think if you simplify the code, you would find that it is much more responsive and probably not require the loading message. In your code, you check every single element in an if statement. Rather than do that, you can check one value, then update all of them accordingly.
Here's a demo: http://jsfiddle.net/jme11/3A4qU/
I made a single change to your HTML to set the initial value of the input button to "Show Details". Then in the following code, you can just check whether the value is Show Details and remove the class that hides the .pickrow and update the value of the button to be "Hide Details" (which is better feedback for the user anyway). Likewise, you can add the .hid class to the pickrow if the button value is not "Show Details". This will also normalize all of the classes regardless if some were individually hidden or shown.
$('#showhide').on('click', function(){
if ($(this).val() === 'Show Details') {
$('.pickrow').removeClass('hid');
$(this).val('Hide Details');
} else {
$('.pickrow').addClass('hid');
$(this).val('Show Details');
}
});
I'm making a simple little website to apply a different formatting style to Reddit posts, I'm trying to add the infinite-scroll jQuery plugin but it doesn't do anything. I tried following the (very simple) instructions on the infinite-scroll page and when it didn't do anything I thought I must have entered something wrongly, but then I just copy/pasted the code from the Masonry/Infinite-Scroll example and it still didn't work. Masonry is working perfectly (finally) but I just can't figure out what is wrong with infinite-scroll. I understand the basics of jQuery and JavaScript, but obviously not as much as most of you people, so could you please help me out and let me know what is wrong? My site is live at reddit.ymindustries.com.
Thanks heaps, you guys have rarely failed me so far.
YM
EDIT: If there aren't enough images to fill up the page on the homepage, visit reddit.ymindustries.com/r/aww for more images.
EDIT 2: I believe I located the issue, it is described here: https://github.com/paulirish/infinite-scroll/issues/5
Now to figure out a fix...
EDIT 3: Added a little bit of a hack in to make it sort of work, but it just seems to loop the second page endlessly now. Hmm...
I think your problem is actually css. Make your page longer that client area height. add more images to $container
Point is, botom edge of your $container need to pass bottom of window so scroll event fires so infinite scroll can react on this event and calculate weather or not edge is reached
BTW, in same cases, for instance, when I shrink my window, the example you set is working.
=== UPDATE ===
I found some time to play with infinitescroll and here is final working script, just set pathParse method in your script
$(function () {
var $container = $('#itemContainer');
$container.imagesLoaded(function () {
$container.masonry({
itemSelector:'.item'
});
});
$container.infinitescroll({
navSelector:'.navigation', // selector for the paged navigation
nextSelector:'.navigation #next', // selector for the NEXT link (to page 2)
itemSelector:'.item', // selector for all items you'll retrieve
bufferPx:40,
debug:true,
columnWidth:function (containerWidth) {
return containerWidth / 5;
},
loading:{
finishedMsg:'No more pages to load.',
img:'http://i.imgur.com/6RMhx.gif'
},
pathParse: function(path,page){
return $(this.nextSelector).attr("href");
}
},
// trigger Masonry as a callback
function (newElements) {
// hide new items while they are loading
var $newElems = $(newElements).css({ opacity:0 });
// ensure that images load before adding to masonry layout
$newElems.imagesLoaded(function () {
// show elems now they're ready
$newElems.animate({ opacity:1 });
$container.masonry('appended', $newElems, true);
});
//console.log("test (never fired :( )");
}
);
});
Now, since your next link will not update by it self (http://reddit.ymindustries.com/?after=t3_yh4av), you need to change the callback to pull out last element from ajax response and change next link... could be something like this
function (newElements) {
// hide new items while they are loading
var $newElems = $(newElements).css({ opacity:0 });
// ensure that images load before adding to masonry layout
// ======> if query parameter after=... is caring filename then do this
var lastImageUrl= $newElements[$newElements.length-1].attr("src");
var lastFileName= lastImageUrl.substring(lastImageUrl.lastIndexOf("/") +1, lastImageUrl.lastIndexOf("."));
$("#next").attr("href", "http://reddit.ymindustries.com/?after="+lastFileName);
$newElems.imagesLoaded(function () {
// show elems now they're ready
$newElems.animate({ opacity:1 });
$container.masonry('appended', $newElems, true);
});
//console.log("test (never fired :( )");
}
You also need to take care of wich version of infinite-scroll your using since if you use the ones that comes with masonry/isotope (version 2.0b2.110713), both need a little hack in order to call the function and not use the predefined array:
//old code, to be changed (line 489)
desturl = path.join(opts.state.currPage);
// new code
desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage);
This is already fixed in the newer versions of infinite-scroll
I had the same problem with jQuery's "infinitescroll" and Masonry. You might just solve this by giving your page more initial items so that the plugin's scrolling detection kicks in.
In WordPress this is under the "Reading" settings. By default WordPress only opens 10 items at a time. You could increase that number to 100/page to be more sure the window will be full initially. I had some code here that was just horrible, turns out I just needed longer pages, not more code.
So it's difficult to test these plugins on large displays if you don't have enough images. Maybe the solution is to scale the images larger on large displays so you're more sure about getting your content below the fold.
If you think someone might get to your website with a really huge display, I'm not sure what the answer is other than showing more items/page and maybe adding $('#masonry').infinitescroll('retrieve'); to your footer to load an extra page just in case.