Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The modal insert dialog is hidden although onAddRow returns a string #1391

Closed
ghost opened this issue Jun 9, 2017 · 9 comments
Closed

The modal insert dialog is hidden although onAddRow returns a string #1391

ghost opened this issue Jun 9, 2017 · 9 comments

Comments

@ghost
Copy link

ghost commented Jun 9, 2017

According to handleSaveBtnClick in Toolbar.js a value/object that is returned by the function assigned to onAddRow in the BootstrapTable options should lead to a notice and the modal not being hidden. This does't work. The reason is that handleAddRow in BootstrapTable.js does call onAddRow without returning the result. It should look like this:

handleAddRow = newObj => {
 const { onAddRow } = this.props.options;
 if (onAddRow) {
    const colInfos = this.store.getColInfos();
    // JB: Added returning the value that onAddRow returns, to pass it to the caller
    const onAddRowResult = onAddRow(newObj, colInfos);
    if (onAddRowResult) {
       return onAddRowResult;
    }
 } 
  ... 

This ensures that a value/object returned by by the function assigned to onAddRow is passed to handleSaveBtnClick. The fix works in my copy of the BoostrapTable code in a production app without issues. We can even get rid ot the (not working) hack in ToolBar.handleSaveBtnClick:

handleSaveBtnClick = (newRow) => {
 if (!this.validateNewRow(newRow)) { // validation fail
   return;
 }
 const msg = this.props.onAddRow(newRow);
 if (msg) {
   notice('error', msg, '');
   this.clearTimeout();
   // shake form and hack prevent modal hide
   this.setState({
     shakeEditor: true
     // JB: This (not working hack) obviously is not needed (anymore)
     // , validateState: 'this is hack for prevent bootstrap modal hide
@AllenFang
Copy link
Owner

@freeboarder42, so you means if the onAddRow function return some error message, we just return and go back to handleSaveBtnClick? so if in this case, wha't the mens you said We can even get rid ot the (not working) hack in ToolBar.handleSaveBtnClick? sorry, I can't get this point :)

@ghost
Copy link
Author

ghost commented Jun 10, 2017

@AllenFang, yes, that's what I mean :-). handleSaveBtnClick checks the return value of onAddRow, but if nothing is returned the code in the if(msg) block will never be executed. What I mean with the hack was setting validateState to 'this is hack for prevent bootstrap modal hide' . Obviously this hack did not work because the block was never executed. Also I just commented it out (as in my code example) and the modal works as expected, and stays open if onAddRow returns an error message.

Anyway, my little addition works, but unfortunately the real world is async. If in onAddRow the row/entity is sent to a web API via AJAX, there is no chance of returning an error message. To solve this I created a custom modal that allows to intercept the click on the Save button, and proceeds only in a success callback. If you're interested I could send you the code.

@AllenFang
Copy link
Owner

@freeboarder42, thanks, I got your point. BTW, did you enable remote mode? and if I pass another callback function to you to handle the error or success case, is that will be helpful for you, right?

@ghost
Copy link
Author

ghost commented Jun 16, 2017

Sorry, just saw your comment. I did not enable remote mode. I solved the issue of handling errors when saving the added row via a REST API by adding a callback that is called by the Save button's onClick method. The callback itself gets a callback passed for the success, and one for the error. If the success callback is called, the onClick method proceeds (and the modal is closed). I attached the source code of my custom dialog.
The usage looks like this:

// Method that creates the custom insert modal dialog
createCustomModalDialog = (onModalClose, onSave, columns, validateState, ignoreEditable) =>
{
   const attributes =
   {
      onModalClose,
      onSave,
      columns,
      validateState,
      ignoreEditable,
      heading: this.state.insertDialogHeading,
      onBeforeInsertRow: this.onBeforeInsertRow.bind(this)
   };
   return (<CustomInsertModalDialog {...attributes}/>);
}

...

// Method that is called before inserting new rows.
// It sets the ID field to a non-empty value that does not exist in the stored entities,
// to avoid the React Boostrap Table to complain that the key value must not be empty or
// that the key value does already exist. This is necessary for key columns with a database
// generated value, that also are hidden in the insert dialog.
// It also stores the passed entity in the database via (faked) AJAX.
onBeforeInsertRow(entity, successCallback, errorCallback)
{
   // This would be sufficient if the entity is saved in onAfterInsertRow: entity.id = -1;
   // We get the next ID value here for demo purposes.
   let maximalIdValue = 0;
   for (let product of this.state.products)
   {
      maximalIdValue = Math.max(maximalIdValue, product.id);
   }
   entity.id = maximalIdValue + 1;

   // Save the new product
   this.saveNewProduct(entity, successCallback, errorCallback);
}

saveNewProduct(product, successCallback, errorCallback)
{
   // Save the entity
   this.setState({ infoMessage: 'Inserting the new product ...', warningMessage: '', errorMessage: '' });

   // TODO: Add the new entity to the database
   // Simulating an asynchronous AJAX call here with setTimeout
   setTimeout(() =>
   {
      let errorOccurred = this.state.simulateRestErrors;

      // Check for errors
      if (errorOccurred === false)
      {
         // The entity was sucessfully added to the database
         this.setState({ infoMessage: 'Saved' });

         // Call the success callback
         successCallback();

         // Add the new entity to the state of the component.
         // Note that this must not happen before the success callback, because the internal bootstrap table
         // code checks if the key of the entity does already exist, and if the entity is pushed to
         // the component's state, it would exist.
         // Note also that we just add the entity to the state to avoid having to copy the whole entity array.
         this.state.products.push(product);
      }
      else
      {
         // In case an error ocurred while adding the new entity to the database,
         // call the error callback with the error (this prevents the insert modal to close,
         // and displays the error message)
         const error =
         {
             heading: 'Error When Saving the Product',
             message: 'Could not add the product to the database'
         };
         errorCallback(error);

         this.setState({ infoMessage: '', warningMessage: '', errorMessage: error.message });
      }
   }, 1000);
}

Cheers

Jürgen

CustomInsertModalDialog.zip

AllenFang added a commit that referenced this issue Jun 17, 2017
@AllenFang
Copy link
Owner

Fixed on v3.4.1, now you can return a string or call a callback function to show the error message and keep the modal open if there's error happen in onAddRow

You can check this to know how it work, thanks

@nguyenhose
Copy link

nguyenhose commented Jun 17, 2017

@AllenFang that's great, but how do i close the modal from callback ? for working around, I used jquery to trigger close button

@AllenFang
Copy link
Owner

AllenFang commented Jun 17, 2017

HI, if you call the callback with explicit string(error message), which means current operation fail so that react-bootstrap-table will not close the modal. But If there's no any error, you can just call the callback without any arguments, react-bootstrap-table will treat this operation as successful then close the modal.

Let me know if you have any concern.

@nguyenhose
Copy link

Ok, it worked. Thank you so much

@ghost
Copy link
Author

ghost commented Jun 17, 2017

@AllenFang: Elegant solution :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants