Skip to content

Commit 4c11e81

Browse files
committed
MAGETWO-54815: Bundle option items are not updated after delete
2 parents d9a19fa + 107e62f commit 4c11e81

File tree

11 files changed

+597
-28
lines changed

11 files changed

+597
-28
lines changed

app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,12 @@ protected function getBundleOptions()
268268
'arguments' => [
269269
'data' => [
270270
'config' => [
271-
'componentType' => 'dynamicRows',
271+
'componentType' => Container::NAME,
272+
'component' => 'Magento_Bundle/js/components/bundle-dynamic-rows',
272273
'template' => 'ui/dynamic-rows/templates/collapsible',
273-
'label' => '',
274274
'additionalClasses' => 'admin__field-wide',
275-
'collapsibleHeader' => true,
276-
'columnsHeader' => false,
277-
'deleteProperty' => false,
278-
'addButton' => false,
279275
'dataScope' => 'data.bundle_options',
276+
'bundleSelectionsName' => 'product_bundle_container.bundle_selections'
280277
],
281278
],
282279
],
@@ -318,14 +315,11 @@ protected function getBundleOptions()
318315
'arguments' => [
319316
'data' => [
320317
'config' => [
321-
'componentType' => DynamicRows::NAME,
322-
'label' => '',
318+
'componentType' => Container::NAME,
319+
'component' => 'Magento_Bundle/js/components/bundle-dynamic-rows-grid',
323320
'sortOrder' => 50,
324321
'additionalClasses' => 'admin__field-wide',
325-
'component' => 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid',
326322
'template' => 'ui/dynamic-rows/templates/default',
327-
'columnsHeader' => false,
328-
'columnsHeaderAfterRender' => true,
329323
'provider' => 'product_form.product_form_data_source',
330324
'dataProvider' => '${ $.dataScope }' . '.bundle_button_proxy',
331325
'identificationDRProperty' => 'product_id',
@@ -343,8 +337,7 @@ protected function getBundleOptions()
343337
'selection_qty' => '',
344338
],
345339
'links' => ['insertData' => '${ $.provider }:${ $.dataProvider }'],
346-
'source' => 'product',
347-
'addButton' => false,
340+
'source' => 'product'
348341
],
349342
],
350343
],
@@ -561,7 +554,7 @@ protected function getBundleSelections()
561554
'componentType' => Container::NAME,
562555
'isTemplate' => true,
563556
'component' => 'Magento_Ui/js/dynamic-rows/record',
564-
'is_collection' => true,
557+
'is_collection' => true
565558
],
566559
],
567560
],
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Copyright © 2016 Magento. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
define([
7+
'underscore',
8+
'Magento_Ui/js/dynamic-rows/dynamic-rows-grid'
9+
], function (_, dynamicRowsGrid) {
10+
'use strict';
11+
12+
return dynamicRowsGrid.extend({
13+
defaults: {
14+
label: '',
15+
columnsHeader: false,
16+
columnsHeaderAfterRender: true,
17+
addButton: false
18+
},
19+
20+
/**
21+
* Initialize elements from grid
22+
*
23+
* @param {Array} data
24+
*
25+
* @returns {Object} Chainable.
26+
*/
27+
initElements: function (data) {
28+
var newData = this.getNewData(data),
29+
recordIndex;
30+
31+
this.parsePagesData(data);
32+
33+
if (newData.length) {
34+
if (this.insertData().length) {
35+
recordIndex = data.length - newData.length - 1;
36+
37+
_.each(newData, function (newRecord) {
38+
this.processingAddChild(newRecord, ++recordIndex, newRecord[this.identificationProperty]);
39+
}, this);
40+
}
41+
}
42+
43+
return this;
44+
},
45+
46+
/**
47+
* Mapping value from grid
48+
*
49+
* @param {Array} data
50+
*/
51+
mappingValue: function (data) {
52+
if (_.isEmpty(data)) {
53+
return;
54+
}
55+
56+
this._super();
57+
}
58+
});
59+
});
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Copyright © 2016 Magento. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
define([
7+
'underscore',
8+
'mageUtils',
9+
'uiRegistry',
10+
'Magento_Ui/js/dynamic-rows/dynamic-rows'
11+
], function (_, utils, registry, dynamicRows) {
12+
'use strict';
13+
14+
return dynamicRows.extend({
15+
defaults: {
16+
label: '',
17+
collapsibleHeader: true,
18+
columnsHeader: false,
19+
deleteProperty: false,
20+
addButton: false
21+
},
22+
23+
/**
24+
* Set new data to dataSource,
25+
* delete element
26+
*
27+
* @param {Array} data - record data
28+
*/
29+
_updateData: function (data) {
30+
var elems = _.clone(this.elems()),
31+
path,
32+
dataArr,
33+
optionBaseData;
34+
35+
dataArr = this.recordData.splice(this.startIndex, this.recordData().length - this.startIndex);
36+
dataArr.splice(0, this.pageSize);
37+
elems = _.sortBy(this.elems(), function (elem) {
38+
return ~~elem.index;
39+
});
40+
41+
data.concat(dataArr).forEach(function (rec, idx) {
42+
if (elems[idx]) {
43+
elems[idx].recordId = rec[this.identificationProperty];
44+
}
45+
46+
if (!rec.position) {
47+
rec.position = this.maxPosition;
48+
this.setMaxPosition();
49+
}
50+
51+
path = this.dataScope + '.' + this.index + '.' + (this.startIndex + idx);
52+
optionBaseData = _.pick(rec, function (value) {
53+
return !_.isObject(value);
54+
});
55+
this.source.set(path, optionBaseData);
56+
this.source.set(path + '.bundle_button_proxy', []);
57+
this.source.set(path + '.bundle_selections', []);
58+
this.removeBundleItemsFromOption(idx);
59+
_.each(rec['bundle_selections'], function (obj, index) {
60+
this.source.set(path + '.bundle_button_proxy' + '.' + index, rec['bundle_button_proxy'][index]);
61+
this.source.set(path + '.bundle_selections' + '.' + index, obj);
62+
}, this);
63+
}, this);
64+
65+
this.elems(elems);
66+
},
67+
68+
/**
69+
* Removes nested dynamic-rows-grid rendered records from option
70+
*
71+
* @param {Number|String} index - element index
72+
*/
73+
removeBundleItemsFromOption: function (index) {
74+
var bundleSelections = registry.get(this.name + '.' + index + '.' + this.bundleSelectionsName),
75+
bundleSelectionsLength = (bundleSelections.elems() || []).length,
76+
i;
77+
78+
if (bundleSelectionsLength) {
79+
for (i = 0; i < bundleSelectionsLength; i++) {
80+
bundleSelections.elems()[0].destroy();
81+
}
82+
}
83+
},
84+
85+
/**
86+
* {@inheritdoc}
87+
*/
88+
processingAddChild: function (ctx, index, prop) {
89+
var recordIds = _.map(this.recordData(), function (rec) {
90+
return parseInt(rec['record_id'], 10);
91+
}),
92+
maxRecordId = _.max(recordIds);
93+
94+
prop = maxRecordId > -1 ? maxRecordId + 1 : prop;
95+
this._super(ctx, index, prop);
96+
}
97+
});
98+
});

app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,15 @@ define([
5252
obj;
5353

5454
if (this.recordData().length && !this.update) {
55-
this.recordData.each(function (recordData) {
55+
_.each(this.recordData(), function (recordData) {
5656
obj = {};
5757
obj[this.map[this.identificationProperty]] = recordData[this.identificationProperty];
5858
insertData.push(obj);
5959
}, this);
6060

61-
this.source.set(this.dataProvider, insertData);
61+
if (insertData.length) {
62+
this.source.set(this.dataProvider, insertData);
63+
}
6264
}
6365
},
6466

@@ -178,7 +180,7 @@ define([
178180
tmpObj = {};
179181

180182
if (data.length !== this.relatedData.length) {
181-
data.forEach(function (obj) {
183+
_.each(data, function (obj) {
182184
tmpObj[this.identificationDRProperty] = obj[this.identificationDRProperty];
183185

184186
if (!_.findWhere(this.relatedData, tmpObj)) {
@@ -193,7 +195,7 @@ define([
193195
/**
194196
* Processing insert data
195197
*
196-
* @param {Array} data
198+
* @param {Object} data
197199
*/
198200
processingInsertData: function (data) {
199201
var changes,

app/code/Magento/Ui/view/base/web/templates/dynamic-rows/templates/collapsible.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
</div>
4444

4545
<button class="action-delete"
46+
data-index="delete_button"
4647
type="button"
4748
title="'Delete'"
4849
click="function(){

dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
use Magento\Mtf\Client\Element\SimpleElement;
1010
use Magento\Bundle\Test\Block\Adminhtml\Catalog\Product\Edit\Section\Bundle\Option;
11-
use Magento\Mtf\Client\Element;
1211
use Magento\Mtf\Client\ElementInterface;
1312
use Magento\Mtf\Client\Locator;
1413
use Magento\Ui\Test\Block\Adminhtml\Section;
@@ -53,6 +52,13 @@ class Bundle extends Section
5352
*/
5453
protected $bundleOptionRow = './tr[%d]';
5554

55+
/**
56+
* Selector for trash can button in bundle option row.
57+
*
58+
* @var string
59+
*/
60+
protected $deleteOption = './tr[%d]//*[@data-index="delete_button"]';
61+
5662
/**
5763
* Get bundle options block.
5864
*
@@ -83,17 +89,49 @@ public function setFieldsData(array $fields, SimpleElement $element = null)
8389
if (!isset($fields['bundle_selections'])) {
8490
return $this;
8591
}
92+
93+
$context = $this->_rootElement->find($this->bundleOptions, Locator::SELECTOR_XPATH);
94+
95+
if (isset($fields['bundle_selections']['value']['bundle_options'])) {
96+
foreach ($fields['bundle_selections']['value']['bundle_options'] as $key => $bundleOption) {
97+
$count = $key + 1;
98+
$itemOption = $context->find(sprintf($this->openOption, $count), Locator::SELECTOR_XPATH);
99+
$isContent = $context->find(sprintf($this->optionContent, $count), Locator::SELECTOR_XPATH)
100+
->isVisible();
101+
if ($itemOption->isVisible() && !$isContent) {
102+
$itemOption->click();
103+
} elseif (!$itemOption->isVisible()) {
104+
$this->_rootElement->find($this->addNewOption)->click();
105+
}
106+
$this->getBundleOptionBlock($count, $context)->fillOption($bundleOption);
107+
}
108+
}
109+
110+
if (isset($fields['bundle_selections']['value']['bundle_options_delete'])) {
111+
$this->deleteFieldsData($fields['bundle_selections']['value']['bundle_options_delete']);
112+
}
113+
114+
return $this;
115+
}
116+
117+
/**
118+
* Delete some bundle options.
119+
*
120+
* @param array $fields
121+
* @return $this
122+
*/
123+
public function deleteFieldsData(array $fields)
124+
{
86125
$context = $this->_rootElement->find($this->bundleOptions, Locator::SELECTOR_XPATH);
87-
foreach ($fields['bundle_selections']['value']['bundle_options'] as $key => $bundleOption) {
88-
$count = $key + 1;
89-
$itemOption = $context->find(sprintf($this->openOption, $count), Locator::SELECTOR_XPATH);
90-
$isContent = $context->find(sprintf($this->optionContent, $count), Locator::SELECTOR_XPATH)->isVisible();
91-
if ($itemOption->isVisible() && !$isContent) {
92-
$itemOption->click();
93-
} elseif (!$itemOption->isVisible()) {
94-
$this->_rootElement->find($this->addNewOption)->click();
126+
foreach (array_keys($fields) as $key) {
127+
$bundleOptionIndex = $key + 1;
128+
$deleteOption = $context->find(
129+
sprintf($this->deleteOption, $bundleOptionIndex),
130+
Locator::SELECTOR_XPATH
131+
);
132+
if ($deleteOption->isVisible()) {
133+
$deleteOption->click();
95134
}
96-
$this->getBundleOptionBlock($count, $context)->fillOption($bundleOption);
97135
}
98136
return $this;
99137
}

0 commit comments

Comments
 (0)