Grid swallows (hide) errors. How to properly manage them instead?

I've been looking through the Grid and DataManager documentation and I can't find a (proper) way to handle errors, with is a critical piece on every app.
In some cases the grid silently ignoring the errors, in some others it just behaves unexpectedly. In either way it is providing a less then ideal user experience.

Let's take this Remote Data sample from the your website:

Open it in Plunker and just change the endpoint to an invalid url, for example by appending any character to the end of it.
Run the application and the grid will render just fine with a message: "No data to display". In this case it is misleading the end user who will never know the grid is actually unable to connect to the data.

In another scenario, I created a custom adaptor based on the JsonAdaptor. I'm trowing an exception in the "batchRequest" method just to see how the grid reacts to it.
The end result is: 
  • I press the save button
  • Get the confirmation dialog
  • Press the Ok button
  • The grid "freezes", the modal "spinner" will take over the screen and the only option left to the end user is to refresh the page
I have to assume I'm missing something that might be really obvious to others.

Thanks in advance,

5 Replies

VA Venkatesh Ayothi Raman Syncfusion Team April 19, 2018 12:35 PM UTC

Hi Emerson, 

Thanks for using Syncfusion products. 

Query #1: “Grid display No data to display while we given a invalid Url for remote data “ 
Yes, we have displayed the empty row with message ‘No records to Display’ when data source didn’t bind to the Grid. But we have trigger the actionFailure event when Grid failed to achieve the desired results. Please refer to the following code example and Help documentation, 
Code example
<ejs-grid #grid [dataSource]='data' (actionFailure)='actionFailure($event)' allowPaging='true' [pageSettings]='pageSettings'> 
        <e-columns> 
. .   . 
        </e-columns> 
    </ejs-grid> 
 
[ts file] 
 
actionFailure(args:any){ 
    console.log(args); 
     
    }} 



Screenshot
 

Query #2: “Waiting spinner always shown while throw the exception in batch Request method” 
We can show the waiting spinner for every grid acitons and hide the waiting spinner in success/failure of Grid actions. But in your scenario, you have throw the exception in sample level using custom adaptor and script error thrown in console window. 
In this case, execution of the program was stopped and waiting spinner shown always. This is the cause of this issue as well as this is the default behavior of the Grid. For this scenario, we suggest you use try and catch function to resolve this issue like as follows or refresh the page. 
 
class SerialNoAdaptor extends JsonAdaptor  { 
   batchRequest(dm: DataManager, changes: CrudOptions, e: RemoteArgs): CrudOptions { 
        let i: number; 
         
         
        
 try { 
  throw new TypeError("Error message"); 
//here we can handle the exception 
} 
catch (e){ 
 
  console.log((<Error>e).message);//conversion to Error type 
        .   .   . 
        return changes; 
    } 
 



Regards, 
Venkatesh Ayothiraman. 



EB EBrito April 19, 2018 02:15 PM UTC

Thanks a lot. 
I went up and down the documentation but looks like i missed the "actionFailure" event (i guess I was too focused on the word "error").

As for Query #2:

Using a custom adaptor was my initial though but I couldn't figure out how to prevent the event propagation in case there was an error.
Your sample code has the same issue I had before creating this post.
To make it easier to understand, here is a slightly modified version of your code:
class SerialNoAdaptor extends JsonAdaptor {

  batchRequest(dm: DataManager, changes: CrudOptions, e: RemoteArgs): CrudOptions {

    let i: number;
    let success: boolean = false;    

    try {
      doSomething(changes);
      success = true;
    }
    catch (e) {
      console.log((<Error>e).message);
    }

    if (success) {
      for (i = 0; i < changes.addedRecords.length; i++) {
        this.insert(dm, changes.addedRecords[i]);
      }
      for (i = 0; i < changes.changedRecords.length; i++) {
        this.update(dm, e.key, changes.changedRecords[i]);
      }
      for (i = 0; i < changes.deletedRecords.length; i++) {
        this.remove(dm, e.key, changes.deletedRecords[i]);
      }
    }

    return changes;
  }

}
As per above code, we don't want to perform any data operations if there was an error. 
The idea is to notify the user and let them try again.

The problem becomes: grid goes back to its original state, the "Update" button is grayed out and all user input is lost even thought there was an error and we couldn't process the data as expected.




MS Mani Sankar Durai Syncfusion Team April 24, 2018 12:42 PM UTC

Hi Emerson, 


We have checked the query and found that you would like to undo the changes even after any failure happens in batch editing. We have considered this as an issue “Need to provide option to prevent refresh when a failure takes place while editing” and it will be included in our next patch release. In this requirement, we will pass the Boolean property as an argument and using that we can refresh the grid or ignoring the refresh. 

Until then we suggest you use the below workaround. 


class SerialNoAdaptor extends JsonAdaptor  { 
   batchRequest(dm: DataManager, changes: CrudOptions, e: RemoteArgs): CrudOptions { 
       let i: number; 
    let success: boolean = false; 
       
  try { 
      doSomething(changes); 
      success = true; 
    } 
    catch (e) { 
      this.batchRequest = true 
        console.log((<Error>e).message); 
      this.mdata = changes;             //place the changes in any of the global variable 
         
    } 
... 
@Component({ 
    selector: 'app-container', 
... 
}) 
export class AppComponent implements OnInit { 
 
    public data: DataManager; 
public editSettings: EditSettingsModel; 
    public toolbar: ToolbarItems[]; 
    public mdata: any; 
    public batchRequest: boolean; 
    ngOnInit(): void { 
... 
    } 
     
    dataBound(args:any){               //method that triggers after any failure happens. Here we have used a dataBound event in grid since the data get refreshed and triggers here. 
      if(this.data.adaptor.batchRequest === true){ 
          let grid = document.getElementById("grid").ej2_instances[0]; 
          for(let i: number = 0; i<this.data.adaptor.mdata.changedRecords.length; i++){ 
             for(let j:number =0 ;j< grid.currentViewData.length; j++){  
               if(this.data.adaptor.mdata.changedRecords[i].OrderID === grid.currentViewData[j].OrderID){ 
                 grid.editModule.updateRow(j,this.data.adaptor.mdata.changedRecords[i]);  //undo the modified data 
               } 
             } 
          } 
           for(let i: number = 0; i<this.data.adaptor.mdata.addedRecords.length; i++){ 
               grid.editModule.addRecord(this.data.adaptor.mdata.changedRecords[i],j);  //undo added record 
            
          } 
           for(let i: number = 0; i<this.data.adaptor.mdata.deletedRecords.length; i++){ 
             for(let j:number =0 ;j< grid.currentViewData.length; j++){ 
               if(this.data.adaptor.mdata.deletedRecords[i].OrderID === grid.currentViewData[j].OrderID){ 
                   grid.editModule.deleteRow(grid.getRowByIndex(i));  //undo deleted record 
               } 
             } 
          } 
        this.data.adaptor.mdata = null; 
      }       
    }   
} 

From the above code example, we have undone the modified, deleted or added record after any failure occurs in batchRequest extends from the custom adaptor.  

Using updataRow, addRecord and deleteRow methods of grid we have retrieved the changes from global variable and bound that changed data again to the grid based on primary key. 

Please refer the documentation link 


We have also prepared a sample based on the requirement and the same can be available from the below link 


Please let us know if you need further assistance.  


Regards, 
Manisankar Durai. 




EB EBrito April 24, 2018 08:58 PM UTC

You mentioned a Boolean property:

[...] we will pass the Boolean property as an argument and using that we can refresh the grid or ignoring the refresh [...]

Will it work with "async" data updates (which is a more realistic scenario)?
Something like this (the same batchUpdate method from the data adaptor):

batchRequest(dm: DataManager, changes: CrudOptions, e: RemoteArgs): CrudOptions {
 
  let i: number;
  let updateModel = this.newUpdateModel();
 
  try {
 
      // extract data from delete and update collections

    this.fromBatchDelete(updateModel, changes);
    this.fromBatchUpdate(updateModel, changes);
 
      // update data on the server
      this.dataService.batchUpdate(updateModel).subscribe(() => {
 
      console.log('done with server updates.');
 
      for (i = 0; i < changes.addedRecords.length; i++) {
        this.insert(dm, changes.addedRecords[i]);
      }
      for (i = 0; i < changes.changedRecords.length; i++) {
        this.update(dm, e.key, changes.changedRecords[i]);
      }
      for (i = 0; i < changes.deletedRecords.length; i++) {
        this.remove(dm, e.key, changes.deletedRecords[i]);
      }
 
        //-> here is where we should tell the grid
        //-> all changes were successfully commited

    });
 
  } catch (e) {
      //-> handle exception, leave grid state as is
    }
 
  return changes;
}
Thanks,



MS Mani Sankar Durai Syncfusion Team April 25, 2018 11:54 AM UTC

Hi Emerson,  
 
Yes, the fix for the issue will work for ‘async’ data also. Here we will provide one Boolean property as an argument for the client-side event. From there we can enable or disable to undo the changes when failure happens while using batch editing of the grid and the fix for the issue will be available on next patch release. 
 
We will appreciate your patience until then. 
 
Regards, 
Manisankar Durai 


Loader.
Up arrow icon