WooCommerce JS event doesn't work using Vanilla JS but works fine with jQuery - wordpress

I have the following code that triggers whenever the cart is updated.
The problem is that the jQuery version works as expected but the Vanilla JS doesn't.
jQuery( document.body ).on('updated_cart_totals', function( event ) {
console.log( 'in here' ); // Works.
} );
document.body.addEventListener( 'updated_cart_totals', function( event ) {
console.log( 'in here too' ); // Doesn't work.
} );
Is there something I am missing?

It appears to be answered before
https://stackoverflow.com/a/41727891/5454218
jQuery uses its own system of event/data binding which inter-operates only one way. In WooCommerce context it's an essential part of its system, so don't shy away from it. No shame in using jQuery when you're already deep in this pile of s**t.

My Answer would be, Yes it's now possible to detect by addAction() and doAction() using Vanilla JS -
wp.hooks.addAction().
wp.hooks.doAction()
How to do - My Approach
// Trigger any jQuery event
$document.trigger( 'test-trigger', [data] );
// Fire action
wp.hooks.doAction( 'test.trigger', data );
// Catch this event from anywhere in JS
wp.hooks.addAction( 'test.trigger', 'cp/test-trigger', function(data) {
console.log('JS Response data', data);
} , 10);
Reference Example of WordPress Core
For reference, Let's see a WordPress heartbeat js's doAction() - https://github.com/WordPress/wordpress-develop/blob/trunk/src/js/_enqueues/wp/heartbeat.js#L460
// heartbeat.js#L460
$document.trigger( 'heartbeat-tick', [response, textStatus, jqXHR] );
wp.hooks.doAction( 'heartbeat.tick', response, textStatus, jqXHR );
// Catch that heartbeat tick from anywhere in JS
wp.hooks.addAction( 'heartbeat.tick', 'cp/heartbeat-tick', function(response, textStatus, jqXHR) {
console.log('heartbeat response', response);
} , 10, 3);

Related

Moving Coupon error code to bottom of woocommerce checkout page [duplicate]

I would like to change the position of all the coupon code-related WooCommerce messages on the checkout page.
I have successfully moved the coupon code form from its original position (top of the checkout page) to after the order details table (woocommerce_review_order_before_payment hook).
But now the coupon code message placement does not make sense, especially for mobile users, therefore I would like to move all of the coupon code-related messages below the coupon form (at the woocommerce_review_order_before_payment hook).
However, it's important that only messages that are related to coupon codes get moved and not all of the messages.
Here's a list of all the WooCommerce messages that are related to coupon codes:
Message
Message type
When
Coupon code already applied!
woocommerce-error
When you try applying a coupon code that has already been applied to your order.
Coupon "coupon-code" does not exist!
woocommerce-error
When you try applying a nonexistent coupon code.
Please enter a coupon code.
woocommerce-error
When you try applying an empty coupon field.
Coupon has been removed.
woocommerce-message
When you successfully remove a coupon code from your order.
Coupon code applied successfully.
woocommerce-message
When you successfully apply a coupon code to your order.
Could someone please help out?
First, As per said #Pavel Vnukov nested forms are not supported and are not part of the w3c standard. so you have added preventDefault so default action should not be taken.
I have fixed some code changes to the #Pavel Vnukov code to work as per your need.
Try the below code.
(function($){
$('.woocommerce-form-coupon-toggle').remove();
$(document).on("click", 'button[name="apply_coupon"]', function(event) {
event.preventDefault();
$form = $('form[name="checkout"]');
$form.block({message:''});
var data = {
security: wc_checkout_params.apply_coupon_nonce,
coupon_code: $( 'input[name="coupon_code"]' ).val()
};
$.ajax({
type: 'POST',
url: wc_checkout_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'apply_coupon' ),
data: data,
success: function( code ) {
$( '.woocommerce-error, .woocommerce-message' ).remove();
$form.removeClass( 'processing' ).unblock();
if ( code ) {
$( 'button[name="apply_coupon"]' ).parent().after( code );
$( document.body ).trigger( 'update_checkout', { update_shipping_method: false } );
}
},
dataType: 'html'
});
});
})(jQuery);
Tested and Works
It looks like a duplication of Move coupon field after checkout payment in Woocommerce?
Standart coupon form can't be placed before confirmation button - because you will include form in form - nested forms are not supported and are not part of the w3c standard.
You can easily move coupon form after confirmation button. The best way to move coupon block to another place is to use code from above question:
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form');
add_action( 'woocommerce_review_order_before_payment', 'woocommerce_checkout_coupon_form' );
Another way is to remove coupon form from it standard position and create a custom input with a button. Than you need to add custom js code like from woocommerce source (wp-content/plugins/woocommerce/assets/js/frontend/checkout.js:536)
$(".custom_apply_coupon_code").on("click", function(event) {
var data = {
security: wc_checkout_params.apply_coupon_nonce,
coupon_code: $( 'input[name="coupon_code"]' ).val()
};
$.ajax({
type: 'POST',
url: wc_checkout_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'apply_coupon' ),
data: data,
success: function( code ) {
$( '.woocommerce-error, .woocommerce-message' ).remove();
$form.removeClass( 'processing' ).unblock();
if ( code ) {
$form.before( code );
$form.slideUp();
$( document.body ).trigger( 'update_checkout', { update_shipping_method: false } );
}
},
dataType: 'html'
});
});
Where code will include success or error message.

Woocommerce disable script opening terms inline

On the checkout page in Woocommerce there is an "I accept terms and conditions" checkbox. The "terms and conditions" is a link, but Woocommerce captures the click event on the link, and instead opens a small popup(?) with the Terms and conditions page.
I would like to disable the script, and have it be just a normal link.
I identified the js code which captures this event. Unfortunately it's a part of checkout.min.js which controls other parts of the checkout experience too, so I would like to keep the rest of the script intact.
i = {
init: function() {
e(document.body).on("click", "a.woocommerce-terms-and-conditions-link", this.toggle_terms)
},
toggle_terms: function() {
if (e(".woocommerce-terms-and-conditions").length)
return e(".woocommerce-terms-and-conditions").slideToggle(), !1
}
};
i.init()
Bonus question, can I change the link to point to an arbitrary url (a pdf in this case)?
cale_b is right.
But because the link already has target="_blank" there is no need for add a new click handler. To archieve that your custom javascript code is load / run after WooCommerce's script you can use wp_add_inline_script.
I use this snippet and it works:
function disable_wc_terms_toggle() {
wp_add_inline_script( 'wc-checkout', "jQuery( document ).ready( function() { jQuery( document.body ).off( 'click', 'a.woocommerce-terms-and-conditions-link' ); } );" );
}
add_action( 'wp_enqueue_scripts', 'disable_wc_terms_toggle', 1000 );
Add this to your theme's functions.php and your done.
You can also do this by removing the woocommerce 'action'. Add this code to your functions.php file:
function stknat01_woocommerce_checkout_t_c_link() {
remove_action( 'woocommerce_checkout_terms_and_conditions', 'wc_terms_and_conditions_page_content', 30 );
}
add_action( 'wp', 'stknat01_woocommerce_checkout_t_c_link' )
WooCommerce uses jQuery, so you can use jQuery's off API to remove the event binding, and then assign your own event listener.
Important: The key to making this work is that your script MUST load / run after WooCommerce's script, otherwise the event won't be there to turn "off". If Woo's script runs after yours, it'll bind the event and yours won't remove it. I've demonstrated one method below, but you might need to use others (such as using a setTimeout):
// no-conflict-safe document ready shorthand
jQuery(function($) {
// wait until everything completely loaded all assets
$(window).on('load', (function() {
// remove the click event, and add your own to redirect
$( document.body )
.off( 'click', 'a.woocommerce-terms-and-conditions-link' )
.on( 'click', location.href='your_full_url_here');
});
});
Next, I anticipate you asking how to open the PDF in a new tab - for answers to that, see this question.
I followed this instructions for the removing inline toggle display of "Terms and conditions". It does not work until following code it is removed from checkout.min.js.
.slideToggle(),!1}},i={init:function(){e(document.body).on("click","a.woocommerce-terms-and-conditions-link",this.toggle_terms)},toggle_terms:function(){if(e(".woocommerce-terms-and-conditions").length)return e(".woocommerce-terms-and-conditions").slideToggle(),!1}};
After removing this line from checkout.min.js my checkout.js is also changed, here it is:
//remove toggle
/*
var wc_terms_toggle = {
init: function() {
$( document.body ).on( 'click', 'a.woocommerce-terms-and-conditions-link', this.toggle_terms );
},
toggle_terms: function() {
if ( $( '.woocommerce-terms-and-conditions' ).length ) {
$( '.woocommerce-terms-and-conditions' ).slideToggle();
return false;
}
}
};
*/
// no-conflict-safe document ready shorthand
jQuery(function($) {
// wait until everything completely loaded all assets
$(window).on('load', (function() {
// remove the click event, and add your own to redirect
$( document.body )
.off( 'click', 'a.woocommerce-terms-and-conditions-link' );
.on( 'click', location.href='https://yoursite.whatever');
});
});
wc_checkout_form.init();
wc_checkout_coupons.init();
wc_checkout_login_form.init();
//wc_terms_toggle.init();
});
Thank you for the script.

Wpcf7 Dom Events not working

This should be very simple but it just does not work and I have no clue why.
Can somebody please explain to me what the problem is?
I have tried my code and the documentation example and nothing works at all.
Link to docs: Contact Form 7 Dom Events
My code:
$('.hollow-form-01 form.wpcf7-form').on('wpcf7submit', function() {
alert('submitted');
});
Documentation Example:
var wpcf7Elm = document.querySelector( '.wpcf7' );
wpcf7Elm.addEventListener( 'wpcf7submit', function( event ) {
alert( "Fire!" );
}, false );

RactiveJS decorator init issue

I am using a decorator for some sliders like the following:
content = new Ractive({
el: '.wrapper',
template: templates.wrapper,
partials: templates,
data : { ... },
decorators: {
carousel: function( node )
{
console.log( 'carousel init' );
carousel = $( node ).owlCarousel({
items: 1,
navigation: false
});
return {
teardown: function () {
console.log( 'carousel destroy' );
carousel.trigger('destroy.owl.carousel').removeClass('owl-carousel owl-loaded');
carousel.find('.owl-stage-outer').children().unwrap();
}
}
}
}
}
What happens is that, as you can see in the logs, when swapping between a template which has inited the carousel to another template that has this decorator as well, the first decorator teardown is being triggered after the new template's decorator is initiated, therefore the carousel on the second template gets torn down and not the one in the first template.
Am I doing something wrong ? Thanks !
UPDATE
I have made a jsfiddle for it here : https://jsfiddle.net/05sq8o2k/6/
Make sure to tap load unsafe scripts if you get the warning because ractivejs cdn does not support https as far as I can see so jsfiddle kind of disagrees with it now.
This seems fixed in the next version of Ractive. Update your fiddle to use: https://cdn.ractivejs.org/edge/ractive.min.js
Kind regards
Bob

js event listener on object (Google Maps)

The following lines of code document what I'm trying to acchieve. In detail, I'm trying to attach an addListener to a DOM object. Sadly it seems that I can't access it.
var dom_obj = document.getElementById( 'dom_obj_id' );
console.log( typeof dom_obj ); // console: object
google.maps.event.addListener( dom_obj, 'click', function() {
// the following two lines don't appear
alert( 'Test - called from addListener' );
console.log( dom_obj );
} );
jQuery( zoom_in ).click(
function() {
// works
alert( 'Test - called via jQuery click function' );
console.log( dom_obj );
return false;
}
);
Searched for hours and found the solution seconds after typing the Q...
Simple as it is: Use addDomListener instead.

Resources