magentodynamic

Display Dynamic SKU on configurable product view Magento


I have this script to show the dynamic sku on select option, but i cannot get working.

Is loading the correct sku, but on select nothing happen.

This code get list of sku on Javascript and update a div on select option for product on configurable product view.

<?php
$_product    = $this->getProduct();
$_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes());
?>
<?php if ($_product->isSaleable() && count($_attributes)):?>
    <dl>
    <?php foreach($_attributes as $_attribute): ?>
        <dt><label class="required"><em>*</em><?php echo $_attribute->getLabel() ?></label></dt>
        <dd<?php if ($_attribute->decoratedIsLast){?> class="last"<?php }?>>
            <div class="input-box">
                <select name="super_attribute[<?php echo $_attribute->getAttributeId() ?>]" id="attribute<?php echo $_attribute->getAttributeId() ?>" class="required-entry super-attribute-select" onchange="return changeSku(this);">
                    <option><?php echo $this->__('Choose an Option...') ?></option>
                  </select>
              </div>
        </dd>
    <?php endforeach; ?>
    </dl>
    <script type="text/javascript">
        var spConfig = new Product.Config(<?php echo $this->getJsonConfig() ?>);
    </script>

<?php endif;?>


<?php
$conf = Mage::getModel('catalog/product_type_configurable')->setProduct($_product);
$col = $conf->getUsedProductCollection()->addAttributeToSelect('*')->addFilterByRequiredOptions();

echo '<script type="text/javascript">';

echo '
document.observe("dom:loaded", function() {
  $("sku-container").update("<strong>Product Id: </strong> Select an option to display Product Id");
});
';
echo ' function changeSku(sel){';       

$itemId = array();           
foreach($col as $simple_product){
$itemId[] = array($simple_product->getSelectLabel() => $simple_product->getSku());
} 

//echo "<pre>";
//print_r($itemId);
//echo "</pre>";

foreach($itemId as $val){
 foreach($val as $k => $v){
echo "\n".'if(sel.options[sel.selectedIndex].value == "'.$k.'"){'."\n";
echo '$("sku-container").update("<strong>Product Id: </strong>'.$v.'");'. "\n";
echo '}';
    }
}

echo "\n".'if(sel.options[sel.selectedIndex].value == ""){'."\n";
echo '$("sku-container").update("<strong>Product Id: </strong> Select an option to display Product Id");'. "\n";
echo '}'; 

echo "}";
echo "\n</script>";
?>

I appreciate any help.

Thanks


Solution

  • The script is almost correct except for $simple_product->getSelectLabel() being a wrong key. No such method/property exists in a simple product model. In order to make the script work, this key should be replaced with a right one - a Product Id. Utilizing product id, it is possible to find the sku of the product being selected.


    So, first of all you need to reorganize itemId array to make it a "productId => productSku" map:

    $productMap = array();
    foreach($col as $simpleProduct){
        $productMap[$simpleProduct->getId()] = $simpleProduct->getSku();
    }
    


    Then you need to change the "onchange" function call to pass Configurable's attribute id to the changeSku() function. Thus the underlying logic is able to search appropriate simple product's attributes.

    onchange="return changeSku(<?php echo $_attribute->getAttributeId() ?>, this);">
    


    And after that you need utilize configurable's config in order to map selected simple product's attribute id to the product id selected:

    function changeSku(confAttributeId, sel) {
        var productMap = <?php echo Mage::helper('core')->jsonEncode($productMap);?>;
        var selectedAttributeId = sel.options[sel.selectedIndex].value;
        if (selectedAttributeId) {
            var options = spConfig.config.attributes[confAttributeId].options;
            var productId = options.find(function (option) {return option.id == selectedAttributeId}).products[0]
            $("sku-container").update("<strong>Product Id: </strong>" + productMap[productId]);
        } else {
            $("sku-container").update("<strong>Product Id: </strong> Select an option to display Product Id");
        }
    }
    


    For your reference, below is the summary of how the whole template looks like (I've beautified it a little):

    <?php
    $_product    = $this->getProduct();
    $_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes());
    ?>
    <?php if ($_product->isSaleable() && count($_attributes)):?>
    <dl>
        <?php foreach($_attributes as $_attribute): ?>
        <dt><label class="required"><em>*</em><?php echo $_attribute->getLabel() ?></label></dt>
        <dd<?php if ($_attribute->decoratedIsLast){?> class="last"<?php }?>>
            <div class="input-box">
                <select name="super_attribute[<?php echo $_attribute->getAttributeId() ?>]" id="attribute<?php echo $_attribute->getAttributeId() ?>" class="required-entry super-attribute-select"
                        onchange="return changeSku(<?php echo $_attribute->getAttributeId() ?>, this);">
                    <option><?php echo $this->__('Choose an Option...') ?></option>
                </select>
            </div>
        </dd>
        <?php endforeach; ?>
    </dl>
    <script type="text/javascript">
        var spConfig = new Product.Config(<?php echo $this->getJsonConfig() ?>);
    </script>
    
        <?php endif;?>
    
    <div id="sku-container"></div>
    
    <?php
    $conf = Mage::getModel('catalog/product_type_configurable')->setProduct($_product);
    $col = $conf->getUsedProductCollection()->addAttributeToSelect('*')->addFilterByRequiredOptions();
    
    $productMap = array();
    foreach($col as $simpleProduct){
        $productMap[$simpleProduct->getId()] = $simpleProduct->getSku();
    }
    ?>
    
    <script type="text/javascript">
    
    document.observe("dom:loaded", function() {
      $("sku-container").update("<strong>Product Id: </strong> Select an option to display Product Id");
    });
    
    function changeSku(confAttributeId, sel) {
        var productMap = <?php echo Mage::helper('core')->jsonEncode($productMap);?>;
        var selectedAttributeId = sel.options[sel.selectedIndex].value;
        if (selectedAttributeId) {
            var options = spConfig.config.attributes[confAttributeId].options;
            var productId = options.find(function (option) {return option.id == selectedAttributeId}).products[0]
            $("sku-container").update("<strong>Product Id: </strong>" + productMap[productId]);
        } else {
            $("sku-container").update("<strong>Product Id: </strong> Select an option to display Product Id");
        }
    }
    </script>
    

    This will do the task you originally needed.


    Also note the following

    1. Your approach won't work for a configurable product with two or more configurable attributes. For that product a final simple product is not known until a user selects values for all the select inputs. So an approach should be changed to check all the selects before outputting SKU.
    2. The code doesn't consider a case, when user edits product configuration, rather than specifying configuration for a new product. You can go to editing mode from the Shopping Cart clicking the Edit link. In such a case all the select inputs will be pre-filled with previously chosen values. But the text will say "Select an option to display Product Id". The script might also produce other Javascript errors in Edit mode. The code should be slightly modified in order to support Edit mode as well.
    3. The template is overfilled with logic. A Magento template should have only simple prints and foreach-iterations. All the methods like $conf->getUsedProductCollection()->addAttributeToSelect('*')->addFilterByRequiredOptions() are better to be moved to block. This reduces code complexity. Hope it helps.