Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply a 'table'-class to a WooCommerce table after AJAX-call

WooCommerce-tables comes with classes like these, out of the box: shop_table shop_table_responsive cart woocommerce-cart-form__contents. So no table-class, which means no nifty Bootstrap-tables.

Huh!

And since overriding the WooCommerce-templates should only be done when absolutely necessary, then let's solve it with JavaScript!

My entire site it encapsulated by a Vue-div, like so:

<div id="app">
  ...
  <table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents">
    ...
    ...
  </table>
  ... 
</div>

So initially I wrote this code, to add the table-class to all tables:

let tableSelectors = [
  '.some-class table',
  '.woocommerce-product-attributes',
  '.woocommerce-cart-form > table'
];
for( let t = 0; t < tableSelectors.length; t++ ){
  let tables = document.querySelectorAll( tableSelectors[t] );
  if( tables ){
    for( let i = 0; i < tables.length; i++ ){
      tables[i].classList.add( 'table' );
    }
  }
}

... Putting that in the mounted(){ ... }-section.

That worked! So far so good.

But WooCommerce is using jQuery quite a lot. And on the cart page, if I change the quantity (and press 'Update'), then the table-contents are updated using AJAX. If you're curious how it works, then you can check it out here.

And when that runs, I assume that WooCommerce grabs the initial cart-template and reloads that whole table; without the newly added table-class. Bah humbug!

So how can I solve this?

  1. I can override the WooCommerce ./cart/cart.php-template and add the class to the template. Seems like quite the overkill for adding a class.

  2. I can scan the DOM for tables every second (or so) and apply the table class, if it's not there. Not cool... Regardless if it's done using jQuery or Vue.

Since the whole table is being replaced in the DOM, then it doesn't work to monitor the current table (using watch(){...} in Vue) and apply the class if it changes, - since it never changes (it's replaced).

I'm unable to find a Hook that I can use.

I also tried using ajaxComplete, but I can see in the network-tab that the XHR-request is firing, but this code here is never doing anything (in the console):

jQuery( document ).ajaxComplete(function( event, xhr, settings ) {
    console.log( 'Test' );
});

Any other suggestions?

like image 851
Zeth Avatar asked Aug 14 '19 18:08

Zeth


1 Answers

You could use the Mutation Observer API to listen for changes to a wrapper element's contents and re-apply the table classes.

This example is lifted nearly verbatim from the sample code on MDN. Clicking the button replaces the contents of the div, which you can see from the console output fires the observer callback.

// Select the node that will be observed for mutations
const targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
const config = {
  childList: true,
  subtree: true
};

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
  for (let mutation of mutationsList) {
    if (mutation.type === 'childList') {
      console.log('A child node has been added or removed.');
    }
  }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

function doUpdate() {
  targetNode.innerText = Math.random();
}

document.querySelector('button').addEventListener('click', doUpdate);
<div id="some-id">(container)</div>
<button>change</button>
like image 116
ray hatfield Avatar answered Sep 29 '22 01:09

ray hatfield