Issues with Datamanager

Hi,
my grid is bound to a datamanager like this:

ngOnInit(): void {
this.data = new DataManager({
url: 'https://localhost:5001/odata/products',
adaptor: new ODataV4Adaptor
});

this.pageSettings = { pageSize: 10 };
this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
}

It retrieved the data and allows the delete action correctly. Problems are: 
  1. After delete grid is empty and I need to navigate to the next page to display the data
  2. Insert does not work. The backend is an ASPnetcore 2.1 OData v4
      [EnableQuery]
    public async Task<IActionResult> Post([FromBody] ProductDTO item)
    {
    try {
    if (item == null) return BadRequest("No item to post");
    var retVal = await _unitOfWork.Products.Upsert(_mapper.Map<Product>(item));
    return Created(_mapper.Map<ProductDTO>(retVal));
    }
    catch (Exception ex) {
    return BadRequest(ex.Message);
    }

    }
    The API works from postman. The api method gets called from the angular side but it looks like the model is not getting bound as the item is null
    (it may have to do with the guid passed as an empty string instead of a null.) 

  3.  Could you please provide a sample where the Post works and also how to patch or update a record (aspnetcore method PUT or PATCH)?

    Thanks!!

8 Replies

MF Mohammed Farook J Syncfusion Team July 19, 2018 12:34 PM UTC

Hi Alberto, 

Thanks for contacting Syncfusion support. 

Please confirm the following details before proceeding your requirement. 

Could you please share the error details when performing crud action. It will be helpful for further analysis and to provide a better solution as soon as possible. You can get the grid action failure details by using ‘actionFailure’ event. Please find the code example for your reference. 

[App.component.html] 

<ejs-grid #grid='' [dataSource]='data' (actionFailure)='actionFailure($event)'> 
    .... 
</ejs-grid> 



[App.component.ts] 

   actionFailure(e: any): void { 
 
        console.log(e.error) 
    } 




Regards, 
J Mohammed Farook 



MF Mohammed Farook J Syncfusion Team July 19, 2018 12:34 PM UTC

Hi Alberto, 

Thanks for contacting Syncfusion support. 

Please confirm the following details before proceeding your requirement. 

Could you please share the error details when performing crud action. It will be helpful for further analysis and to provide a better solution as soon as possible. You can get the grid action failure details by using ‘actionFailure’ event. Please find the code example for your reference. 

[App.component.html] 

<ejs-grid #grid='' [dataSource]='data' (actionFailure)='actionFailure($event)'> 
    .... 
</ejs-grid> 



[App.component.ts] 

   actionFailure(e: any): void { 
 
        console.log(e.error) 
    } 




Regards, 
J Mohammed Farook 



AB Alberto Bonfiglio July 20, 2018 07:01 PM UTC

Hello Mohammed,
here is the error message:
error: TypeError: Cannot convert undefined or null to object ... Render.dataManagerSuccess

And this is what i see in the network page of google devtools:
      1. {Id: "", Name: "", Description: "", Material: "", Availability: "", Price: null, Featured: false,…}



When I try posting with postman if i pass an empty ("id": null) id it works, if I pass an empty string ("id": "" ) it fails.

Is there any way to intercept the datamanager save event (if any, I couldn't find an API published for the datamanager ) and modify the object to be saved on the fly?

Actually I just noticed that not all the DTO properties are passed back...

Further debugging the issue seems to be that the odata api expects a guid or null  and the grid or data manager send an empty string. Furthermore there are some properties wich are arrays of strings or objects (like the additionalPictures property)
and if empty they get sent back as a n empty string rather than an empty array. How do I fix this?


Cheers,

Alberto


MF Mohammed Farook J Syncfusion Team July 23, 2018 12:12 PM UTC

Hi Alberto, 

Thanks for your update. 


We have validated the reported issue , we have changed null value instead to empty string by using ‘read’ function when saving record with Guid( as empty ). Please find the code example. 



import { Column, EditSettingsModel, ToolbarItems, IEditCell } from '@syncfusion/ej2-ng-grids'; 

<ejs-grid [datasource]='data' [editsettings]='editSettings' [toolbar]='toolbar' height='273px'> 
    <e-columns> 
        <e-column field='OrderID' headertext='Order ID' textalign='Right' [edit]='dpParams' isprimarykey='true' width=100></e-column> 
        <e-column field='CustomerID' headertext='Customer ID' width=120 [edit]='dpParams'></e-column> 
        . . . 
    </e-columns> 
</ejs-grid> 

[app.component.ts] 

. . . 
export class AppComponent implements OnInit { 
public dpParams: IEditCell; 
 
    ngOnInit(): void { 
      . . . 
    this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true }; 
    this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel']; 
    this.dpParams = { 
    read: () => { 
        const value = !args.value? null: args.value; 
        return value; 
    }, 


So you can override the value from default. In such a way you can use the similar way for your additional properties also. 

If you have faced any difficulties, please share your grid code example. it would be helpful for us to find the solution at earliest. 

Regards, 
J Mohammed Farook 



AB Alberto Bonfiglio July 24, 2018 04:04 AM UTC

Thank you Mohammed,
I was able to figure it out looking at other posts. This forum is really good and you guys do a very good job of answering timely.

However I also fount that part of the issue is that for some reason after making sure the post values are correct, the data is persisted correctly by the API but I get an error when the grid tries to refresh itself. Does the Datamanager expect a response like :
{"odata.context": "blah blah",
 "value" : [    {"id":"b79a6aa2-ed65-400c-8f7d-42052412b0b4","name":"test"}]
} from the POST action?

The Aspnetcore Odata controller gives back a response without the value field like 
{"@odata.context":"https://localhost:5001/odata/$metadata#Products/$entity",
  "id":"b79a6aa2-ed65-400c-8f7d-42052412b0b4","name":"test"
}

[EnableQuery]
public async Task<IActionResult> Post([FromBody] ProductDTO item)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
try {
if (item == null) return BadRequest("No item to post");
var insertedItem = await _unitOfWork.Products.Upsert(_mapper.Map<Product>(item));
return Created(_mapper.Map<ProductDTO>(insertedItem));
// return Created(SingleResult.Create(insertedItem)) throws an exception here
}
catch (Exception ex) {
return BadRequest(ex.Message);
}
}

Any idea how to fix this?

Additional:
I have put some console log calls in my code. It looks like the actionbegin save is called and completes succesfully. Immediately after that The actionFailure is triggered. 
it shows  error:
TypeError: Cannot convert undefined or null to object at Function.keys () at Render.push../node_modules/@syncfusion/ej2-grids/dist/es6/ej2-grids.es5.js.Render.dataManagerSuccess (https://localhost:5001/app-modules-admin-admin-module.js:26268:26) at https://localhost:5001/app-modules-admin-admin-module.js:26156:54 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (https://localhost:5001/polyfills.js:2705:26) at Object.onInvoke (https://localhost:5001/vendor.js:56101:33) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (https://localhost:5001/polyfills.js:2704:32) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (https://localhost:5001/polyfills.js:2455:43) at https://localhost:5001/polyfills.js:3189:34 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (https://localhost:5001/polyfills.js:2738:31) at Object.onInvokeTask (https://localhost:5001/vendor.js:56092:33)




RN Rahul Narayanasamy Syncfusion Team July 24, 2018 01:20 PM UTC

Hi Alberto, 

From the error description “TypeError: Cannot convert undefined or null to object at Function.keys ()” we suspect that the server return empty or null data after saving added record. Please check and ensure whether any empty response returned from the server. To know more above the adding operation in grid, please refer to the below procedure. 

  1. While saving the grid sends the added record to the server as follows.
 
 
  1. After saving the server has to return the added data as follows.
 
 
  1. Now the grid will once again call the server to update the added records in the view, which should return the response as follows.
 

Please use the above method to troubleshoot the add operation in your application and we suggest you to look into the response from the server after saving record and get back to us if you still faced the issue. 

Regards, 
Rahul Narayanasamy. 



AB Alberto Bonfiglio July 24, 2018 03:42 PM UTC

Hello Rahul,
I get a 201 

and it seems the data is returned well.


However it crashes before the grid can call the server to refresh the data.

Here is my component if it helps. A lot of the events are trapped just to pinpoint where the error occurs...

import { uuid } from 'uuid/v4';
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { GridComponent, PageSettingsModel, EditSettingsModel, ToolbarItems, EJ2Intance } from '@syncfusion/ej2-ng-grids';
import { Column } from '@syncfusion/ej2-ng-grids';
import { Dialog } from '@syncfusion/ej2-popups';
import { FileInfo, Uploader } from '@syncfusion/ej2-ng-inputs';

import { DataManager, ODataV4Adaptor } from '@syncfusion/ej2-data';

import { ConfigService} from '../../../../services';
import { ProductCard } from '../../../../models/product';

@Component({
selector: 'app-product-manager',
templateUrl: './product-manager.component.html',
styleUrls: ['./product-manager.component.scss']
})

export class ProductManagerComponent implements OnInit, OnDestroy {
private _url;

public data: DataManager;
public pageSettings: PageSettingsModel;
public toolbar: ToolbarItems[];
public editSettings: EditSettingsModel;
public dpParams;
public dpParams1;
public dppParams;
public uploadObj: Uploader;
public elem;

@ViewChild('grid')
public gridObj: GridComponent;

/*
public imageArray = (field: string, data: Object, column: Object) => {
return data[field].map((s: { picture: string}) => { return s.picture ; }).join(' ');
}
*/

constructor(private configService: ConfigService) {
this._url = this.configService.getConfig().webApiEndpointUrl + 'Products';
}

ngOnInit(): void {
this.data = new DataManager({
url: this._url,
adaptor: new ODataV4Adaptor
});

this.pageSettings = { pageSize: 10 };
this.editSettings = { showDeleteConfirmDialog: true, allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' };
this.toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel'];
}

public actionBegin(args): void {
console.log(`actionbegin ---> ${args.requestType}`);
if (args.requestType === 'beginEdit') {
console.log(`actionbegin ---> ${args.requestType} start`);
// console.log(args.rowData);
console.log(`actionbegin ---> ${args.requestType} end`);
}
if (args.requestType === 'save') {
console.log(`actionbegin ---> ${args.requestType} start`);
args.data.id = null;
args.data.tenantId = null;
args.data.type = 'product';
args.data.active = true;
args.data.name = 'Shoes';
args.data.description = 'Big ones';
args.data.price = 0.00;
args.data.picture = '';
args.data.featured = false;
args.data.categories = [];
args.data.collections = [];
args.data.material = 'Cuoio in acciaio inossidabile';
args.data.availability = 'After months';
args.data.additionalPictures = [];
console.log(`actionbegin ---> ${args.requestType} complete!`);
}
}

public actionComplete(args): void {
console.log('actionComplete!', args);
if (args.requestType === 'beginEdit' || args.requestType === 'add') {
const dialog: Element = this.gridObj.element.querySelector('#' + this.gridObj.element.id + '_dialogEdit_wrapper');
const dialogInst: Dialog = (<EJ2Intance>dialog).ej2_instances[0];
dialogInst.header = 'Product Editor';
dialogInst.allowDragging = true;
dialogInst.showCloseIcon = true;
}
}

public dataSourceChanged(args): void {
console.log('dataSourceChanged!', args);
}


public dataBound(args): void {
console.log('dataBound!', args);
}
public rowDataBound(args): void {
console.log('rowDataBound!', args);
}
public dsEvent(args): void {
console.log('dsEvent!', args);
}

public dataStateChange(args): void {
console.log('dataStateChange!', args);
}

public actionFailure(args: any): void {
console.log('actionFailure!', args);
}

ngOnDestroy() {
}
}

<div class="product-manager container">
<h3>Product Managerh3>
<ejs-grid #grid [dataSource]="data" [allowSelection]="true" [allowSorting]='true'
[allowFiltering]='true' [allowPaging]="true" [pageSettings]="pageSettings" [toolbar]="toolbar"
[editSettings]="editSettings"
(actionBegin)='actionBegin($event)' (actionFailure)='actionFailure($event)' (actionComplete)="actionComplete($event)"
(dataSourceChange)='dataSourceChanged($event)' (dataBound)='dataBound($event)'
(rowDataBound)='rowDataBound($event)' (dataSource)="dsEvent($event)" (dataStateChange)='dataStateChange($event)'
>
<e-columns>
<e-column field= "id" headerText="Product ID" width="130" isPrimaryKey='true' >e-column>
<e-column field= "name" headerText="Product Name" width="150">e-column>
<e-column field= "description" headerText="Description" width="150">e-column>
<e-column field= "material" headerText="Material" width="150">e-column>
<e-column field= "availability" headerText="Availability" width="150">e-column>
<e-column field= "price" headerText="Price" editType= 'numericedit' width="100">e-column>
<e-column field= "featured" headerText="Featured" editType= 'booleanedit' width="100">e-column>
<e-column field= "picture" headerText="1" width="150">e-column>
<e-column field= "additionalPictures" headerText="2" width="150">e-column>
<e-column field= "categories" headerText="3" width="100">e-column>
<e-column field= "collections" headerText="4" width="100">e-column>

<e-column field= "tenantId" [edit]='dpParams1' headerText="5" width="100">e-column>


<e-column field= "active" headerText="Active" editType= 'booleanedit' width="100">e-column>
e-columns>
ejs-grid>
div>



AB Alberto Bonfiglio July 24, 2018 03:58 PM UTC

Here is the console output 


Loader.
Up arrow icon