All we need is an easy explanation of the problem, so here it is.
To create a backend form via ui_component, I define following in the config file to display buttons save and saveAndContinue Button
<item name="buttons" xsi:type="array">
<item name="save" xsi:type="string">namespace\module\Block\Adminhtml\Edit\SaveButton</item>
<item name="save_and_continue" xsi:type="string">namespace\module\Block\Adminhtml\Edit\SaveAndContinueButton</item>
</item>
Respectively, two files SaveButton.php
and SaveAndContinueButton.php
are created and both implement ButtonProviderInterface
As I know, button is mainly rendered from a getButtonData
function. See SaveAndContinueButton.php
public function getButtonData()
{
$TodoItemId = $this->getTodoItemId();
$data = [];
if ($TodoItemId) {
$data = [
'label' => __('Save and Continue Edit'),
'class' => 'save',
'data_attribute' => [
'mage-init' => [
'button' => ['event' => 'saveAndContinueEdit'],
],
],
'sort_order' => 80,
];
}
return $data;
}
The data_attribute
is where that I don’t understand. How does it know which file to handle save request?
If we check the SaveButton.php
, We saw
$data = [
'label' => __('Save TodoItem'),
'class' => 'save primary',
'data_attribute' => [
'mage-init' => ['button' => ['event' => 'save']],
'form-role' => 'save',
],
'sort_order' => 90,
];
I know in the ui_component config file, there is
<item name="submit_url" xsi:type="url" path="path/to/save"/>
Both action successfully execute same Save.php
file and it makes sense. What confuse me much is data_attribute
and how does SaveAndContinueButton
pass parameter “back
” so that it knows to stay at the same page instead of go to grid (normally grid is entry point of a form, aka edit page).
If we take another look at the deleteButton
, it’s another landscape
$data = [
'label' => __('Delete'),
'class' => 'delete',
'on_click' => 'deleteConfirm(\'' . __(
'Are you sure you want to do this?'
) . '\', \'' . $this->getDeleteUrl() . '\')',
'sort_order' => 20,
];
It directly executes the onClick JavaScript event. Any idea/suggestion will be appreciated. thanks
One more question: what’s the different of data_attribute
and on_click
? or advantage one over another one?
How to solve :
I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.
Method 1
I don’t have a full explanation, but I have an idea.
All elements rendered with mage-init
will/should be handled by some javascript code.
You are linking these buttons to a form, and the form is handled by this js file lib/web/mage/backend/form.js
where a jquery ui widget is created.
These are the options for the widget
options: {
handlersData: {
save: {},
saveAndContinueEdit: {
action: {
args: {
back: 'edit'
}
}
},
preview: {
target: '_blank'
}
}
},
you can see a saveAndContinueEdit
in there somewhere inside handlersData
.
Looking for the usages of handlersData
you end up in _beforeSubmit
where some magic happens (I don’t really understand everything in there), and at one point _processData
is called.
Moving to _processData
you will see something like this
if (attrName === 'action') {
data[attrName] = this._getActionUrl(attrValue);
}
this means that the action
of the form is changed based on the button pressed.
the _getActionUrl
function looks like this
_getActionUrl: function(data) {
if ($.type(data) === 'object') {
return this._buildURL(this.oldAttributes.action, data.args);
} else {
return $.type(data) === 'string' ? data : this.oldAttributes.action;
}
},
you can see in there data.args
involved. The same variable in the widget options for saveAndContinueEdit
.
Conclusion: When you set the role saveAndContinueEdit
toa submit button, the action of the form is changed via js and back/edit
is added to the url.
on_click
is transformed to the onclick
event and simply called.
I honestly have no idea why there are 2 ways of doing this. Maybe the delete
actions didn’t get refactored yet.
Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0