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?
- 
 1I have save and continue , but it redirects to magento admin page not found errorJaisa– Jaisa2018年02月08日 10:30:51 +00:00Commented Feb 8, 2018 at 10:30
- 
 What are the files needed to add save and continueJaisa– Jaisa2018年02月08日 10:31:12 +00:00Commented Feb 8, 2018 at 10:31
1 Answer 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.