What you were expecting:
Working buttons after not successful response from server: Confirm and Cancel
What happened instead:
Disabled buttons after not successful response from server:

Steps to reproduce:
Delete button on Toolbar section;Confirm button in the opened window;500 Internal Server Error for example;Delete button on Toolbar section again;Cancel and Confirm.Related code:
const UserEditToolbar = <Toolbar {...props} >
<SaveButton label="Save" redirect="list" submitOnEnter={true} />
<CancelButton basePath={props.basePath} />
<DeleteWithConfirmButton {...props}/>
</Toolbar>;
const UserEdit = (props) => (
<Edit {...props}>
<TabbedForm toolbar={<UserEditToolbar />} >
<FormTab label="User Information">
...
</FormTab>
</TabbedForm>
</Edit>
);
Environment
This seems similar to #3244 : after failed request, the UI breaks.
Can you reproduce the issue on that CodeSandbox please?
This will help maintainers confirm and fix the issue.
@Kmaschta Yes, sure. Give me some time for this...
Link to CodeSandbox.
So, I have replaced every buttons in PostEdit page and left only DeleteWithConfirmButton.
Steps to reproduce:
Delete button on Toolbar section;Confirm button in the opened window;Yep, reproduced. Thanks a lot!
The state change is done when the request succeed, but should be done also when the request fail.
It should be a quick fix.
The disabled is based on loading state which is set to be true before calling onConfirm (crudDelete). The function crudDelete, onSuccess refreshes the page and hence you don't have to care about loading state again but onFailure simply displays the notification and loading remains true and so as disabled. Is there any way to access its response so that loading state can be handled accordingly? @Kmaschta @fzaninotto
This might not be as easy as I thought.
The <Confirm> component store the loading state, but doesn't have a way to unset it.
Can this be done if we add a callback on the failure of crudDelete like:
export interface CrudDeleteAction {
readonly type: typeof CRUD_DELETE;
readonly payload: RequestPayload;
readonly meta: {
resource: string;
fetch: typeof DELETE;
onSuccess: {
notification: NotificationSideEffect;
redirectTo: RedirectionSideEffect;
refresh: RefreshSideEffect;
basePath: string;
};
onFailure: {
notification: NotificationSideEffect;
callback: CallbackSideEffect;
};
};
}
and then passing the callback in Confirm making the loading state false?
@djhi @Kmaschta
I override the entire component and simply change the internal confirm state to false on handleConfirm.
Maybe is not the most flexible way, but you get the component working correctly.
// ...
class Confirm extends Component {
state = { loading: false };
handleConfirm = e => {
e.stopPropagation();
this.setState({ loading: true }); // <-- Just changing true to false here makes it work.
this.props.onConfirm();
};
// ...
In fact, the loading state should not be internal to the Confirm component, but handled outside, by the calling component. As it is a breaking change, we'll only be able to fix it in v3.
Fixed by #3647
Most helpful comment
Fixed by #3647