Skip to content

Commit dcc1086

Browse files
committed
MAGETWO-52974: Configurable product options not saved when editing
2 parents f231724 + d95ad45 commit dcc1086

File tree

11 files changed

+197
-8
lines changed

11 files changed

+197
-8
lines changed

app/code/Magento/Checkout/CustomerData/DefaultItem.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ protected function doGetItemData()
7070
'item_id' => $this->item->getId(),
7171
'configure_url' => $this->getConfigureUrl(),
7272
'is_visible_in_site_visibility' => $this->item->getProduct()->isVisibleInSiteVisibility(),
73+
'product_id' => $this->item->getProduct()->getId(),
7374
'product_name' => $this->item->getProduct()->getName(),
7475
'product_sku' => $this->item->getProduct()->getSku(),
7576
'product_url' => $this->getProductUrl(),

app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,9 +898,15 @@ public function getSelectedAttributesInfo($product)
898898
$value = $value->getSource()->getOptionText($attributeValue);
899899
} else {
900900
$value = '';
901+
$attributeValue = '';
901902
}
902903

903-
$attributes[] = ['label' => $label, 'value' => $value];
904+
$attributes[] = [
905+
'label' => $label,
906+
'value' => $value,
907+
'option_id' => $attributeId,
908+
'option_value' => $attributeValue
909+
];
904910
}
905911
}
906912
}

app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,14 @@ public function testGetSelectedAttributesInfo()
660660

661661
$this->assertEquals(
662662
$this->_model->getSelectedAttributesInfo($productMock),
663-
[['label' => 'attr_store_label', 'value' => '']]
663+
[
664+
[
665+
'label' => 'attr_store_label',
666+
'value' => '',
667+
'option_id' => 1,
668+
'option_value' => ''
669+
]
670+
]
664671
);
665672
}
666673

app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
*/
77
-->
88
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
9+
<head>
10+
<link src="Magento_ConfigurableProduct::js/configurable-customer-data.js"/>
11+
</head>
912
<update handle="catalog_product_view_type_configurable"/>
1013
<body/>
1114
</page>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require([
2+
'jquery',
3+
'Magento_ConfigurableProduct/js/options-updater'
4+
], function ($, Updater) {
5+
'use strict';
6+
7+
var selectors = {
8+
formSelector: '#product_addtocart_form'
9+
},
10+
configurableWidgetName = 'mageConfigurable',
11+
widgetInitEvent = 'configurable.initialized',
12+
13+
/**
14+
* Sets all configurable attribute's selected values
15+
*/
16+
updateConfigurableOptions = function () {
17+
var configurableWidget = $(selectors.formSelector).data(configurableWidgetName);
18+
19+
if (!configurableWidget) {
20+
return;
21+
}
22+
configurableWidget.options.values = this.productOptions || {};
23+
configurableWidget._configureForValues();
24+
},
25+
updater = new Updater(widgetInitEvent, updateConfigurableOptions);
26+
27+
updater.listen();
28+
});

app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ define([
5353

5454
// Setup/configure values to inputs
5555
this._configureForValues();
56+
57+
$(this.element).trigger('configurable.initialized');
5658
},
5759

5860
/**
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
define([
2+
'jquery',
3+
'Magento_Customer/js/customer-data'
4+
], function ($, customerData) {
5+
'use strict';
6+
7+
var selectors = {
8+
formSelector: '#product_addtocart_form',
9+
productIdSelector: '#product_addtocart_form [name="product"]'
10+
},
11+
cartData = customerData.get('cart'),
12+
productId = $(selectors.productIdSelector).val(),
13+
14+
/**
15+
* set productOptions according to cart data from customer-data
16+
*
17+
* @param {Object} data - cart data from customer-data
18+
* @returns {Boolean} - whether the new options differ from previous
19+
*/
20+
setProductOptions = function (data) {
21+
var changedProductOptions;
22+
23+
if (!(data && data.items && data.items.length && productId)) {
24+
return false;
25+
}
26+
changedProductOptions = data.items.find(function (item) {
27+
return item['product_id'] === productId;
28+
});
29+
changedProductOptions = changedProductOptions && changedProductOptions.options &&
30+
changedProductOptions.options.reduce(function (obj, val) {
31+
obj[val['option_id']] = val['option_value'];
32+
33+
return obj;
34+
}, {});
35+
36+
if (JSON.stringify(this.productOptions || {}) === JSON.stringify(changedProductOptions || {})) {
37+
return false;
38+
}
39+
40+
this.productOptions = changedProductOptions;
41+
42+
return true;
43+
},
44+
45+
/**
46+
* Listens to update of cart data or options initialization and update selected option according to customer data
47+
*
48+
*/
49+
listen = function () {
50+
cartData.subscribe(function (updateCartData) {
51+
if (this.setProductOptions(updateCartData)) {
52+
this.updateOptions();
53+
}
54+
}.bind(this));
55+
$(selectors.formSelector).on(this.eventName, function () {
56+
this.setProductOptions(cartData());
57+
this.updateOptions();
58+
}.bind(this));
59+
},
60+
61+
/**
62+
* Updater constructor function
63+
*
64+
*/
65+
Updater = function (eventName, updateOptionsCallback) {
66+
if (this instanceof Updater) {
67+
this.eventName = eventName;
68+
this.updateOptions = updateOptionsCallback;
69+
this.productOptions = {};
70+
}
71+
};
72+
73+
Updater.prototype.setProductOptions = setProductOptions;
74+
Updater.prototype.listen = listen;
75+
76+
return Updater;
77+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © 2016 Magento. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
9+
<head>
10+
<link src="Magento_Swatches::js/configurable-customer-data.js"/>
11+
</head>
12+
</page>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require([
2+
'jquery',
3+
'Magento_ConfigurableProduct/js/options-updater'
4+
], function ($, Updater) {
5+
'use strict';
6+
7+
var selectors = {
8+
formSelector: '#product_addtocart_form',
9+
swatchSelector: '.swatch-opt'
10+
},
11+
swatchWidgetName = 'mageSwatchRenderer',
12+
widgetInitEvent = 'swatch.initialized',
13+
14+
/**
15+
* Sets all configurable swatch attribute's selected values
16+
*/
17+
updateSwatchOptions = function () {
18+
var swatchWidget = $(selectors.swatchSelector).data(swatchWidgetName);
19+
20+
if (!swatchWidget || !swatchWidget._EmulateSelectedByAttributeId) {
21+
return;
22+
}
23+
swatchWidget._EmulateSelectedByAttributeId(this.productOptions);
24+
},
25+
updater = new Updater(widgetInitEvent, updateSwatchOptions);
26+
27+
updater.listen();
28+
});

app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ define([
266266
if (this.options.jsonConfig !== '' && this.options.jsonSwatchConfig !== '') {
267267
this._sortAttributes();
268268
this._RenderControls();
269+
$(this.element).trigger('swatch.initialized');
269270
} else {
270271
console.log('SwatchRenderer: No input data received');
271272
}
@@ -1066,6 +1067,30 @@ define([
10661067
}, this));
10671068
},
10681069

1070+
/**
1071+
* Emulate mouse click or selection change on all swatches that should be selected
1072+
* @param {Object} [selectedAttributes]
1073+
* @private
1074+
*/
1075+
_EmulateSelectedByAttributeId: function (selectedAttributes) {
1076+
$.each(selectedAttributes, $.proxy(function (attributeId, optionId) {
1077+
var elem = this.element.find('.' + this.options.classes.attributeClass +
1078+
'[attribute-id="' + attributeId + '"] [option-id="' + optionId + '"]'),
1079+
parentInput = elem.parent();
1080+
1081+
if (elem.hasClass('selected')) {
1082+
return;
1083+
}
1084+
1085+
if (parentInput.hasClass(this.options.classes.selectClass)) {
1086+
parentInput.val(optionId);
1087+
parentInput.trigger('change');
1088+
} else {
1089+
elem.trigger('click');
1090+
}
1091+
}, this));
1092+
},
1093+
10691094
/**
10701095
* Get default options values settings with either URL query parameters
10711096
* @private

0 commit comments

Comments
 (0)