Displaying configurable products with options on one page can be problem because Javascript in Magento is setup to work only with one configurable product.
You can write your own Javascript or U can reuse Magento code.
To accomplish that we need to modify product Javascript (js/varien/product.js) and configurable (catalog\product\view\type\options\configurable.phtml) select element template.
In configurable.phtml call our new JS class (we will create that class later in article) and add product id to configurable select element class.
configurable.phtml:
<?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_<?php echo $_product->getId()?> ">
<option><?php echo $this->__('Choose an Option...') ?></option>
</select>
</div>
</dd>
<?php endforeach; ?>
</dl>
<script type="text/javascript">
var spConfig_<?php echo $_product->getId()?> = new Inchoo_Product.Config(<?php echo $this->getJsonConfig() ?>);
</script>
<?php endif;?>
Then create Javascript file and Javascript class.
Copy javascript code from js/varien/product.js for configurable product (use own namespace to avoid JS collision with Magento).
if(typeof Inchoo_Product =='undefined') {
var Inchoo_Product = {};
}
/**************************** CONFIGURABLE PRODUCT **************************/
Inchoo_Product.Config = Class.create();
Inchoo_Product.Config.prototype = {
Because we change selector name we have to modify our JS code to work with new selector.
var settingsClassToSelect = '.super-attribute-select_'+this.config.productId; this.settings = $$(settingsClassToSelect);
Magento code is stripping “attribute” string from class of configurable select element but we also have to strip product id (we added product id to class name in configurable.phtml).
// fill state
this.settings.each(function(element){
var attributeId = element.id.replace(/[a-z]*/, '');
attributeId = attributeId.replace(/_.*/, '');
........
fillSelect: function(element){
var attributeId = element.id.replace(/[a-z]*/, '');
attributeId = attributeId.replace(/_.*/, '');
Now we can have multiple configurable products with options on same page.
Update, as requested complete JS file
product.js:
if(typeof Inchoo_Product =='undefined') {
var Inchoo_Product = {};
}
/**************************** CONFIGURABLE PRODUCT **************************/
Inchoo_Product.Config = Class.create();
Inchoo_Product.Config.prototype = {
initialize: function(config){
this.config = config;
this.taxConfig = this.config.taxConfig;
var settingsClassToSelect = '.super-attribute-select_'+this.config.productId;
this.settings = $$(settingsClassToSelect);
this.state = new Hash();
this.priceTemplate = new Template(this.config.template);
this.prices = config.prices;
this.settings.each(function(element){
Event.observe(element, 'change', this.configure.bind(this))
}.bind(this));
// fill state
this.settings.each(function(element){
var attributeId = element.id.replace(/[a-z]*/, '');
attributeId = attributeId.replace(/_.*/, '');
if(attributeId && this.config.attributes[attributeId]) {
element.config = this.config.attributes[attributeId];
element.attributeId = attributeId;
this.state[attributeId] = false;
}
}.bind(this))
// Init settings dropdown
var childSettings = [];
for(var i=this.settings.length-1;i>=0;i--){
var prevSetting = this.settings[i-1] ? this.settings[i-1] : false;
var nextSetting = this.settings[i+1] ? this.settings[i+1] : false;
if(i==0){
this.fillSelect(this.settings[i])
}
else {
this.settings[i].disabled=true;
}
$(this.settings[i]).childSettings = childSettings.clone();
$(this.settings[i]).prevSetting = prevSetting;
$(this.settings[i]).nextSetting = nextSetting;
childSettings.push(this.settings[i]);
}
// Set default values - from config and overwrite them by url values
if (config.defaultValues) {
this.values = config.defaultValues;
}
var separatorIndex = window.location.href.indexOf('#');
if (separatorIndex != -1) {
var paramsStr = window.location.href.substr(separatorIndex+1);
var urlValues = paramsStr.toQueryParams();
if (!this.values) {
this.values = {};
}
for (var i in urlValues) {
this.values[i] = urlValues[i];
}
}
this.configureForValues();
document.observe("dom:loaded", this.configureForValues.bind(this));
},
configureForValues: function () {
if (this.values) {
this.settings.each(function(element){
var attributeId = element.attributeId;
element.value = (typeof(this.values[attributeId]) == 'undefined')? '' : this.values[attributeId];
this.configureElement(element);
}.bind(this));
}
},
configure: function(event){
var element = Event.element(event);
this.configureElement(element);
},
configureElement : function(element) {
this.reloadOptionLabels(element);
if(element.value){
this.state[element.config.id] = element.value;
if(element.nextSetting){
element.nextSetting.disabled = false;
this.fillSelect(element.nextSetting);
this.resetChildren(element.nextSetting);
}
}
else {
this.resetChildren(element);
}
//this.reloadPrice();
// Calculator.updatePrice();
},
reloadOptionLabels: function(element){
var selectedPrice;
if(element.options[element.selectedIndex].config){
selectedPrice = parseFloat(element.options[element.selectedIndex].config.price)
}
else{
selectedPrice = 0;
}
for(var i=0;i<element.options.length;i++){
if(element.options[i].config){
element.options[i].text = this.getOptionLabel(element.options[i].config, element.options[i].config.price-selectedPrice);
}
}
},
resetChildren : function(element){
if(element.childSettings) {
for(var i=0;i<element.childSettings.length;i++){
element.childSettings[i].selectedIndex = 0;
element.childSettings[i].disabled = true;
if(element.config){
this.state[element.config.id] = false;
}
}
}
},
fillSelect: function(element){
var attributeId = element.id.replace(/[a-z]*/, '');
attributeId = attributeId.replace(/_.*/, '');
var options = this.getAttributeOptions(attributeId);
this.clearSelect(element);
element.options[0] = new Option(this.config.chooseText, '');
var prevConfig = false;
if(element.prevSetting){
prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];
}
if(options) {
var index = 1;
for(var i=0;i<options.length;i++){
var allowedProducts = [];
if(prevConfig) {
for(var j=0;j<options[i].products.length;j++){
if(prevConfig.config.allowedProducts
&& prevConfig.config.allowedProducts.indexOf(options[i].products[j])>-1){
allowedProducts.push(options[i].products[j]);
}
}
} else {
allowedProducts = options[i].products.clone();
}
if(allowedProducts.size()>0){
options[i].allowedProducts = allowedProducts;
element.options[index] = new Option(this.getOptionLabel(options[i], options[i].price), options[i].id);
element.options[index].config = options[i];
index++;
}
}
}
},
getOptionLabel: function(option, price){
var price = parseFloat(price);
if (this.taxConfig.includeTax) {
var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
var excl = price - tax;
var incl = excl*(1+(this.taxConfig.currentTax/100));
} else {
var tax = price * (this.taxConfig.currentTax / 100);
var excl = price;
var incl = excl + tax;
}
if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
price = incl;
} else {
price = excl;
}
var str = option.label;
if(price){
if (this.taxConfig.showBothPrices) {
str+= ' ' + this.formatPrice(excl, true) + ' (' + this.formatPrice(price, true) + ' ' + this.taxConfig.inclTaxTitle + ')';
} else {
str+= ' ' + this.formatPrice(price, true);
}
}
return str;
},
formatPrice: function(price, showSign){
var str = '';
price = parseFloat(price);
if(showSign){
if(price<0){
str+= '-';
price = -price;
}
else{
str+= '+';
}
}
var roundedPrice = (Math.round(price*100)/100).toString();
if (this.prices && this.prices[roundedPrice]) {
str+= this.prices[roundedPrice];
}
else {
str+= this.priceTemplate.evaluate({price:price.toFixed(2)});
}
return str;
},
clearSelect: function(element){
for(var i=element.options.length-1;i>=0;i--){
element.remove(i);
}
},
getAttributeOptions: function(attributeId){
if(this.config.attributes[attributeId]){
return this.config.attributes[attributeId].options;
}
},
reloadPrice: function(){
var price = 0;
var oldPrice = 0;
for(var i=this.settings.length-1;i>=0;i--){
var selected = this.settings[i].options[this.settings[i].selectedIndex];
if(selected.config){
price += parseFloat(selected.config.price);
oldPrice += parseFloat(selected.config.oldPrice);
}
}
optionsPrice.changePrice('config', {'price': price, 'oldPrice': oldPrice});
optionsPrice.reload();
return price;
if($('product-price-'+this.config.productId)){
$('product-price-'+this.config.productId).innerHTML = price;
}
this.reloadOldPrice();
},
reloadOldPrice: function(){
if ($('old-price-'+this.config.productId)) {
var price = parseFloat(this.config.oldPrice);
for(var i=this.settings.length-1;i>=0;i--){
var selected = this.settings[i].options[this.settings[i].selectedIndex];
if(selected.config){
price+= parseFloat(selected.config.price);
}
}
if (price < 0)
price = 0;
price = this.formatPrice(price);
if($('old-price-'+this.config.productId)){
$('old-price-'+this.config.productId).innerHTML = price;
}
}
}
}





This sounds like something I might need. Not sure I quiet get what you mean though.
If I have a configurable product in two different colors, will this make me able to show them both but to point to one single url?
Please explain further!
This tutorial is for more than one different configurable product on same page.
You have one configurable product with different color (multiple simple products). So U can use your configurable product url for your simple products with different colors.
How do you get multiple configurable products onto one page in the first place? I’m looking to create a grouped product which allows multiple configurable products to be associated to it. Any ideas how I can acheive this?
U can use grouped product with configurable but it is out of scope of this tutorial. This tutorial is more suited for situations in which you use configurable product not as part of grouped product. For example for widget where you display all configurable product with options in some category.
Hi, i found your tutorial and i’m really want it but i’m a bit of confuse on how to do it. can you show me what would be the final code in configurable.php and in the product.js?
Hello, @jun complete source code for product.js and configurable.js is posted.
Hi Goran,
I’ve been trying to do this but I’ve run into a few problems. What I did was:
1. Add to the catalog_product_layer on the catalog.xml file the block related to configurable product (so I can call the configurable block from the list.phtml file).
2. The problem is that on the configurable block the first line:
$this->getProduct();
doesn’t get any product, and then it just can’t get anything.
How have you solved this?
Thanks!
Hi again!
I’ve just used the:
And then I could see the configurable options. But only the first configurable option is working. I think we have to change id’s and other things…
Sorry:
Mage::unregister(‘product’)
Mage::register(‘product’, $_product)
OK, I have to merge all my answers…..
The thing is that the register/unregister seems to not work well: it always gets the same id. How did you solve this?
Thanks!
Ok, I thinks it’s time to talk about viagra!!
We finally got it!! We were calling the same block again and again, so it was always the same. So we decided to dynamically create the block directly from the template:
$this->getLayout()->createBlock(‘catalog/product_view_type_configurable’, ”, array(‘template’=> ‘catalog/product/view/type/options/configurable.phtml’))->toHtml(); ?>
Glad you solve it:)
Thank Goran a lot. That’s what i looking for.
Hi,
Can you please tell me that how can i load configurable option via ajax call and load them into dom elements ?
Hi ,
Please put demo of yours tutorial.
I like used configurable product in site http://www.pruneshop.com/carteras/cartera-de-cuero-p008463qm.html . I want to do similar in my site .Please answer – is your code do similar ?
Thanks
Hi Rusian,
You can take a look at this (note that I could write this thanks to Goran!):
http://www.catgento.com/adding-configurable-product-options-to-category-list-in-magento/
Hi ,
I did steps like you explain. Code working – I can add in cart choose option , but can’t change image in list when made option ( maybe some I made wrong). Can see here http://www.modatadnes.com/shop/woman.html , but only my product 1856 is now configurable. Can you give me advice how can change image when change option configurable product in catalog page.
Thanks again Pau and Goran
Where can i specify the second configurable product id in the code.
Please help me on this.
Hey!
Thank you for your great solution!
But i have one problem: How do you handle the price reload?
On the product page is missing var optionsPrice = new Product.OptionsPrice(….
=> exception, no price update after attribute selection possible
Did you have any idea?
Hi,
how can I reload price on option change?
Can’t reload the price.
Finally I can reload the price
Hello,
I develop a module to compose a grouped product with configurable product.
With your solution a retrieve well production option, I already manage the recursive item for configurable product in grouped product.
How can i do to add all configurable product to cart after selection? in the same form…
Hi
i m new to magento can you please help
i want the configurable drop down in crosssell option (checkout option)
please help….
I am setting up an apparel store for a client, they have a selection of items and each item has a color selection, however, not all of the items come in the same colors. Originally I set up each item with its own color attribute with the colors specific to that item, however, when you do a seach, you then end up with multiple “Color” sections listed on the left that you can use to narrow your search. Is there any way to set one “Color” attribute with all of the options, and then specify which options a specific product has access to?
Hi, can somepne please tell me how they got the different getJsonConfig() for the products.
Ive used a config product page, and brough more config products in….but i cant get anything from the second config product’s getJsonConfig() method when called.
Ive tried bypassing this….but just doesnt seem right…having to copy a quite bit of code into an extension to get this to work correctly.
The main config product for the page is fine….just the included products that have issues here.
Ive tried calling and using config-product-model object, tried instantiating the product-config block itself (but cant get it populated with all the data it needs i think to product a jsonconfig string.)
How can i easily generate this string, or get the getJsonConfig function itself working?
thx
@Faroque: How did you achieve the price reload? Can you post your solution?
Hi,
I’m new magento developer and implement this code but fetchning some proble Attribute name is display but attribute value not display in dropdown.
please help me.
This is an extremely helpful tutorial, but there is still work to do if you want to use VarienForm validation, which refers to an attribute id. If you’re just using the default attributeN format for the select box, and you have multiple products with attributeN, VarienForm validation will target the first select box with that id. Better to append the product id to the select box directly rather in Inchoo_Product. That way, both validation and options fill work properly.
Hi,
very help full post.
But can you explain how to define option prices for multiple products.
Hi,
Basically I’ve got your tutorial working in my site. But instead of assigning the correct simple product related to the attributes/options its assigning the attributes to the configurable product, which only has the standard/lowest price. Any thing you know to change it from assigning attributes to assigning the correct simple product like in the product
Below is an example of a product added in the product page and one in the list. The top one is from the list, which wont add the new prices and the bottom is from the product which would add a different price depending on the options selected
http://www.hillsidegroup.co.uk/lordwholesale-configurable-options.jpg.
Any help would be greatly appreciated, thank you.
hi
i really liked your document and its really helpful but can you pls explain same method for bundle product too. so it will be very helpful for me.
Thanks
Hi,
Is we can merge two configurable product JSON into one ?
How can i skip the product view page for configurable products when add to cart?. Please help me…