The thing is to add additional data with quantity to Configurable Product JSON before creating product detail page. Then override swatch-renderer.js
to catch clicks on swatches.
Don't forget to include [Vendor]/[Module]/registration.php
and [Vendor]/[Module]/etc/module.xml
to your extension
1) [Vendor]/[Module]/Block/ConfigurableProduct/Product/View/Type/Configurable.php
File content:
namespace [Vendor]\[Module]\Block\ConfigurableProduct\Product\View\Type;
use Magento\Framework\Json\EncoderInterface;
use Magento\Framework\Json\DecoderInterface;
use Magento\CatalogInventory\Api\StockRegistryInterface;
class Configurable
{
protected $jsonEncoder;
protected $jsonDecoder;
protected $stockRegistry;
public function __construct(
EncoderInterface $jsonEncoder,
DecoderInterface $jsonDecoder,
StockRegistryInterface $stockRegistry
) {
$this->jsonDecoder = $jsonDecoder;
$this->jsonEncoder = $jsonEncoder;
$this->stockRegistry = $stockRegistry;
}
// Adding Quantitites (product=>qty)
public function aroundGetJsonConfig(
\Magento\ConfigurableProduct\Block\Product\View\Type\Configurable $subject,
\Closure $proceed
)
{
$quantities = [];
$config = $proceed();
$config = $this->jsonDecoder->decode($config);
foreach ($subject->getAllowProducts() as $product) {
$stockitem = $this->stockRegistry->getStockItem(
$product->getId(),
$product->getStore()->getWebsiteId()
);
$quantities[$product->getId()] = $stockitem->getQty();
}
$config['quantities'] = $quantities;
return $this->jsonEncoder->encode($config);
}
}
2) [Vendor]/[Module]/etc/frontend/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\ConfigurableProduct\Block\Product\View\Type\Configurable">
<plugin name="[vendor]_configurable_product_configurable"
type="[Vendor]\[Module]\Block\ConfigurableProduct\Product\View\Type\Configurable"
sortOrder="1"/>
</type>
</config>
3) [Vendor]/[Module]/view/frontend/requirejs-config.js
var config = {
map: {
'*': {
'Magento_Swatches/js/swatch-renderer':'[Vendor]_[Module]/js/swatch-renderer'
}
}
};
4) Copy original file /module-swatches/view/frontend/web/js/swatch-renderer.js
to [Vendor]/[Module]/view/frontend/web/js/swatch-renderer.js
In function _OnClick
insert before $widget._Rebuild();
code below:
var errorFlag = true;
var selectedSwatch = {};
// Compare objects
function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
// If values of same property are not equal,
// objects are not equivalent
if (a[propName] !== b[propName]) {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
// Foreach every attribute and check. If only one undefined (not selected) - nothing won't work
$('.swatch-attribute').each(function () {
var $element = $(this),
attrId = $element.attr('attribute-id'),
optionSelected = $element.attr('option-selected');
if(typeof optionSelected == "undefined"){
errorFlag = true;
return false;
} else {
selectedSwatch[attrId] = optionSelected;
errorFlag = false;
}
});
// Show stock notification to user
if(errorFlag == false){
var allTheProducts = $widget.options.jsonConfig.index;
$.each(allTheProducts, function(index, value) {
if(isEquivalent(selectedSwatch, value)){
// Quantity of selected simple product by ID
var qty = $widget.options.jsonConfig.quantities[index];
console.log('Simple product ID: '+index+', quantity: '+qty);
if(qty == 1){
$('.stock-notification').html("ONLY 1 LEFT IN STOCK");
} else if(qty > 1){
$('.stock-notification').html("IN STOCK");
} else {
$('.stock-notification').html("OUT OF STOCK");
}
}
});
} else {
$('.stock-notification').html("");
}