Empty data set when loading JSON using TXDataWebDataSet.SetJSOnData method

Hello,

When I try to load a resulting JSON String from a call to and XData server I end up with a blank record.

This is the code I use to load the dataset:

procedure TfDashboard.xdGetUserListLoad(Response: TXDataClientResponse);
const
  cJSONNameValue = 'value';
var
  lValue: TJSONValue;
begin
  lValue := TJSONObject.ParseJSONValue(Response.responseText);
  try
    if lValue is TJSONObject then
    begin
      xUserDataList.SetJsonData(TJSONObject(lValue).Values[cJSONNameValue].Value);
      xUserDataList.Open;
      ShowMessage(xUserDataListUSER_FIRST_NAME.AsString);
      WebDBGrid1.Refresh;
    end;
  finally
    lValue.Free;
  end;
end;

And this is the JSON value received:

{
    "value": "{"data":{"rows":[{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","TELEPHONE_NUMBER":"8275309","COMPANY_NAME":"The Continental","FACILITY_NAME":"JW's House"}]}}"
}

I am using a TQuey component from IBDAC (Devart) to generate the resulting JSON.

I suspect that the JSON elements are incorrect. However, I wasn't able to find what elements is TXDataWebDataSet expecting. Can you please, point out where I can find more information?

If the JSON is compatible with the dataset, what am I missing for the datat to appear on the WebDBGrid?

Thanks,

Alan

There is this example in documentation, have you checked it?

procedure TForm1.LoadWithXDataClient;

  procedure OnSuccess(Response: TXDataClientResponse);
  begin
    XDataWebDataset1.SetJsonData(Response.Result);
    XDataWebDataset1.Open;
  end;

begin
  XDataWebClient1.List('artist', '$filter=startswith(Name, ''New'')', @OnSuccess);
end;

No I did not. However, after reading it and reading my code I can see that I am doing basically the same.

This is the code that call my server:

procedure TfDashboard.GetUserList;
begin
  xdGetUserList.RawInvoke('IUserDataService.GetUsersList', []);
end;

And this is the code that handles the response:

procedure TfDashboard.xdGetUserListLoad(Response: TXDataClientResponse);
const
  cJSONNameValue = 'value';
var
  lValue: TJSONValue;
begin
  lValue := TJSONObject.ParseJSONValue(Response.responseText);
  try
    if lValue is TJSONObject then
    begin
      xUserDataList.SetJsonData(TJSONObject(lValue).Values[cJSONNameValue].Value);
      xUserDataList.Open;
      ShowMessage(xUserDataListUSER_FIRST_NAME.AsString);
      WebDBGrid1.Refresh;
    end;
  finally
    lValue.Free;
  end;
end;

Furthermore, I tried to load the XML directly using this code and I still come up empty handed.

procedure TfDashboard.xdGetUserListLoad(Response: TXDataClientResponse);
const
  cJSONNameValue = 'value';
var
  lValue: TJSONValue;
 begin
  lValue := TJSONObject.ParseJSONValue(Response.responseText);
  try
    if lValue is TJSONObject then
    begin
      xUserDataList.Close;

//      xUserDataList.SetJsonData(TJSONObject(lValue).Values[cJSONNameValue].Value);

      xUserDataList.SetJsonData('[{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","TELEPHONE_NUMBER":"8275309","COMPANY_NAME":"The Continental","FACILITY_NAME":"JW''s House"}]');

      xUserDataList.SetJsonData(TJSObject(Response.Result)[cJSONNameValue]);

      xUserDataList.Open;
     
    end;
  finally
    lValue.Free;
  end;

And lastly, I decided to verify that I can display anything at all in the grid and added some data to the dataset using:

      xUserDataList.Open;
      xUserDatalist.Append;
      xUserDataListUSER_ID.AsInteger := 1;
      xUserDataListCOMPANY_ID.AsInteger := 1;
      xUserDataListUSER_NAME.AsString := 'jw';
      xUserDataListUSER_FIRST_NAME.AsString := 'John';
      xUserDataList.Post;

That generated blank record, followed by the record I appended using code as seen below:

How come this line of code only produces an blank record?

xUserDataList.SetJsonData('[{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","TELEPHONE_NUMBER":"8275309","COMPANY_NAME":"The Continental","FACILITY_NAME":"JW''s House"}]');

Is there anything missing on my JSON?

Hi Alan,

First and foremost, use Response.Result, not Response.responseText.

So your code would be more like this:

procedure TfDashboard.xdGetUserListLoad(Response: TXDataClientResponse);
const
  cJSONNameValue = 'value';
var
  lValue: TJSONValue;
begin
  lValue := Response.Result;
  try
    if lValue is TJSONObject then
    begin
      xUserDataList.SetJsonData(TJSONObject(lValue).Values[cJSONNameValue].Value);
      xUserDataList.Open;
      ShowMessage(xUserDataListUSER_FIRST_NAME.AsString);
      WebDBGrid1.Refresh;
    end;
  finally
    lValue.Free;
  end;
end;

Second, JavaScript (and in turn Web Core) is not strongly typed, so you will never be 100% sure of the result structure just from compiling code.

When in doubt, call console.log on all structures so you are 100% sure what you are receiving and what you are dealing with it.

But that I mean you could call console.log(Response.Result) and also on the Values[cJSONNameValue] and also on the final object/array you are passing to SetJsonData. So you are sure it's the structure you are expecting. If you still haven't solve it, paste such results of console.log calls here so we also know what you are receiving.

The code you pasted calls SetJSONData twice so if that's the code you are using it's not exactly what you are passing to the dataset. Again, please let us know the exact JSON/JS structure of all steps until it gets passed to the dataset.

Hi Wagner,

Thank you for your reply.

I tried to use your code and got [*Error] f_Dashboard.pas(103): Incompatible types: got "JSValue" expected "TJSONValue".

Is there a typecast missing? Or, perhaps LValue needs to be of a different type?

Thanks,

Alan

I see the problem with your code, you are mixing TJSON* objects with TJS* objects. Here is correct code:

procedure TfDashboard.xdGetUserListLoad(Response: TXDataClientResponse);
const
  cJSONNameValue = 'value';
var
  lValue: JSValue;
begin
  lValue := Response.Result;
  try
    if JS.IsObject(lValue) then
    begin
      xUserDataList.SetJsonData(TJSObject(lValue).Values[cJSONNameValue].Value);
      xUserDataList.Open;
      ShowMessage(xUserDataListUSER_FIRST_NAME.AsString);
      WebDBGrid1.Refresh;
    end;
  finally
    lValue.Free;
  end;
end;

Hi Wagner,

Close but no cigar. This line is giving me an error:

 xUserDataList.SetJsonData(TJSObject(lValue).Values[cJSONNameValue].Value);

The error is [Error] f_Dashboard.pas(108): illegal qualifier "." after "lValue:JSValue".
I believe that the object confusion that you pointed out on your prior answer continues.
And because I am so new to this aspect of TMS I am leaning on you for guidance on how to solve it.

Thanks,

Alan

Sorry but I'm not compiling the code I'm sending you, this is just guidelines.
Try this:

xUserDataList.SetJsonData(TJSObject(lValue)[cJSONNameValue]);

This is general Delphi (not even Web Core) practice: if something goes wrong and you need better debugging, break your line that has several accessor in many different local variables so you can better inspect what's going on, for example, instead of:

xUserDataList.SetJsonData(TJSObject(lValue)[cJSONNameValue]);

do something like

Obj1 := TJSObject(lValue);
SomeValue := Obj1[cJSONNameValue];
xUserDataList.SetJsonData(SomeValue);

And again, inspect the value of each step, and in the case of Web Core, you can call console.log(value) to see the full and exact value in the browser console.

I am still unable to load data to a TxDataWebDataset component using SetJsonData. Despite having data on my JSON object I end up with a blank line. Theis is the line that attempts to load the data:

 xUserDataList.SetJsonData(TJSObject(lValue)[cJSONNameValue]);

I also added a line to spit out the JSON that I am trying to load using the console,:

  console.log(TJSObject(lValue)[cJSONNameValue]);

This is the output of the cosole.log line:

> f_Dashboard.pas:108 {"data":{"rows":[{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","TELEPHONE_NUMBER":null,"COMPANY_NAME":"The Continental","FACILITY_NAME":"JW's House"}]}}

And this is a formatted view of such data:

{
	"data": {
		"rows": [
			{
				"USER_ID": 1,
				"COMPANY_ID": 1,
				"USER_NAME": "jw",
				"USER_FIRST_NAME": "John",
				"USER_LAST_NAME": "Wick",
				"TELEPHONE_NUMBER": null,
				"COMPANY_NAME": "The Continental",
				"FACILITY_NAME": "JW's House"
			}
		]
	}
}

Why is it that the TxDataWebDataSet is not loading this JSON?
Thanks,

Alan

Because as the log indicates, your data is inside property "data", "rows". So you must use something like this:

  resultObj := TJSObject(lValue)[cJSONNameValue];
  dataObj := TJSObject(resultObj)['data'];
  rowsArray := TJSObject(dataObj)['rows'];
  xUserDataList.SetJsonData(rowsArray);

Did as you suggested and ended up with the following JSON Array being feed to the SetJasonData method:

f_Dashboard.pas:108 [{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","COMPANY_NAME":"The Continental","FACILITY_NAME":"JW's House"}]

which formatted looks like this:

[
	{
		"USER_ID": 1,
		"COMPANY_ID": 1,
		"USER_NAME": "jw",
		"USER_FIRST_NAME": "John",
		"USER_LAST_NAME": "Wick",
		"COMPANY_NAME": "The Continental",
		"FACILITY_NAME": "JW's House"
	}
]

And I still get a blank record instead of the intended data.

I am not sure why. Isn't this what the SetJasonData is execting as a JSON Object?

Alan

As with any development, you should try to isolate the problem and reduce the test project to a minimum.

Since you know now that the server is responding correctly, you can completely remove the server and use this:

Data := TJSJson.parse('[{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","TELEPHONE_NUMBER":"8275309","COMPANY_NAME":"The Continental","FACILITY_NAME":"JW''s House"}]'

Which simulates the server response.
Then just use:

    xUserDataList.SetJsonData(Data);

Maybe even in a completely empty project, and see why it's not working.

Did as you suggested and I still come up with a blank grid. This leads me to inquire, that perhaps we have been pursuing the wrong problem.
Let me restate what I am doing, and, perhaps, something will trigger.

I am using a TxDataWebDataset as an in-memory table to load the retrieved JSON from my server.

The Jason is the same as stated on your reply:

Data := TJSJson.parse('[{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","TELEPHONE_NUMBER":"8275309","COMPANY_NAME":"The Continental","FACILITY_NAME":"JW''s House"}]'

The JSON above is being loaded using the SetJsonData w/o any errors.

After I load the JSON I end up with a blank record.

Not sure what else can be wrong in this. Can it be that I am improperly using the TxDataWebDataset object?

Again, isolate the problem. Create a new project. Investigate what's different from a minimal working project and your application.

Setting data into the dataset is as simple as this:

procedure TForm1.WebButton1Click(Sender: TObject);
var
  Data: JSValue;
begin
  Data := TJSJson.parse('[{"USER_ID":1,"COMPANY_ID":1,"USER_NAME":"jw","USER_FIRST_NAME":"John","USER_LAST_NAME":"Wick","TELEPHONE_NUMBER":"8275309","COMPANY_NAME":"The Continental","FACILITY_NAME":"JW''s House"}]');
  XDataWebDataSet1.SetJsonData(Data);
  XDataWebDataSet1.Open;
end;

I created a barebone project with what I need to test and I got this:

db.pas:1863  Uncaught ObjectFHelpContext: 0FJSError: Error: Connection not assigned
    at Object.Create$1 (http://127.0.0.1:8000/Project1/Project1.js:3647:23)
    at c.$create (http://127.0.0.1:8000/Project1/Project1.js:366:19)
    at Object.DatabaseError (http://127.0.0.1:8000/Project1/Project1.js:80304:31)
    at Object.CheckConnection (http://127.0.0.1:8000/Project1/Project1.js:137376:45)
    at Object.CheckConnected (http://127.0.0.1:8000/Project1/Project1.js:137372:12)
    at Object.InitializeFieldDefinitions (http://127.0.0.1:8000/Project1/Project1.js:137427:12)
    at Object.InternalInitFieldDefs (http://127.0.0.1:8000/Project1/Project1.js:137424:12)
    at Object.InternalOpen (http://127.0.0.1:8000/Project1/Project1.js:124065:12)
    at Object.DoInternalOpen (http://127.0.0.1:8000/Project1/Project1.js:77948:12)
    at Object.OpenCursor (http://127.0.0.1:8000/Project1/Project1.js:78767:68)message: "Connection not assigned"stack: "Error: Connection not assigned\n    at Object.Create$1 (http://127.0.0.1:8000/Project1/Project1.js:3647:23)\n    at c.$create (http://127.0.0.1:8000/Project1/Project1.js:366:19)\n    at Object.DatabaseError (http://127.0.0.1:8000/Project1/Project1.js:80304:31)\n    at Object.CheckConnection (http://127.0.0.1:8000/Project1/Project1.js:137376:45)\n    at Object.CheckConnected (http://127.0.0.1:8000/Project1/Project1.js:137372:12)\n    at Object.InitializeFieldDefinitions (http://127.0.0.1:8000/Project1/Project1.js:137427:12)\n    at Object.InternalInitFieldDefs (http://127.0.0.1:8000/Project1/Project1.js:137424:12)\n    at Object.InternalOpen (http://127.0.0.1:8000/Project1/Project1.js:124065:12)\n    at Object.DoInternalOpen (http://127.0.0.1:8000/Project1/Project1.js:77948:12)\n    at Object.OpenCursor (http://127.0.0.1:8000/Project1/Project1.js:78767:68)"[[Prototype]]: ObjectFMessage: "Connection not assigned"FStack: "Error: Connection not assigned\n    at Object.Create$1 (http://127.0.0.1:8000/Project1/Project1.js:3647:23)\n    at c.$create (http://127.0.0.1:8000/Project1/Project1.js:366:19)\n    at Object.DatabaseError (http://127.0.0.1:8000/Project1/Project1.js:80304:31)\n    at Object.CheckConnection (http://127.0.0.1:8000/Project1/Project1.js:137376:45)\n    at Object.CheckConnected (http://127.0.0.1:8000/Project1/Project1.js:137372:12)\n    at Object.InitializeFieldDefinitions (http://127.0.0.1:8000/Project1/Project1.js:137427:12)\n    at Object.InternalInitFieldDefs (http://127.0.0.1:8000/Project1/Project1.js:137424:12)\n    at Object.InternalOpen (http://127.0.0.1:8000/Project1/Project1.js:124065:12)\n    at Object.DoInternalOpen (http://127.0.0.1:8000/Project1/Project1.js:77948:12)\n    at Object.OpenCursor (http://127.0.0.1:8000/Project1/Project1.js:78767:68)"[[Prototype]]: Object$ancestor: {$ancestor: {…}, $class: {…}, $classname: 'Exception', $parent: {…}, $module: {…}, …}$class: {$ancestor: {…}, $class: {…}, $classname: 'EDatabaseError', $parent: {…}, $module: {…}, …}$classname: "EDatabaseError"$fullname: "DB.EDatabaseError"$module: {$name: 'DB', $intfuseslist: Array(6), $impluseslist: Array(2), $state: 5, $intfcode: ƒ, …}$name: "EDatabaseError"$parent: {$name: 'DB', $intfuseslist: Array(6), $impluseslist: Array(2), $state: 5, $intfcode: ƒ, …}$rtti: {name: 'EDatabaseError', $module: {…}, class: {…}, members: {…}, names: Array(0), …}[[Prototype]]: Object

Not sure of what to make of this error message as this same unit works on my current project. But I went ahead and added a connection information to the dataset and got this:

db.pas:1863  Uncaught ObjectFHelpContext: 0FJSError: Error: EntitySetName not specified.
    at Object.Create$1 (http://127.0.0.1:8000/Project1/Project1.js:3647:23)
    at c.$create (http://127.0.0.1:8000/Project1/Project1.js:366:19)
    at Object.DatabaseError (http://127.0.0.1:8000/Project1/Project1.js:80304:31)
    at Object.CheckEntitySetName (http://127.0.0.1:8000/Project1/Project1.js:137379:46)
    at Object.InitializeFieldDefinitions (http://127.0.0.1:8000/Project1/Project1.js:137428:12)
    at Object.InternalInitFieldDefs (http://127.0.0.1:8000/Project1/Project1.js:137424:12)
    at Object.InternalOpen (http://127.0.0.1:8000/Project1/Project1.js:124065:12)
    at Object.DoInternalOpen (http://127.0.0.1:8000/Project1/Project1.js:77948:12)
    at Object.OpenCursor (http://127.0.0.1:8000/Project1/Project1.js:78767:68)
    at Object.SetActive (http://127.0.0.1:8000/Project1/Project1.js:78800:18)message: "EntitySetName not specified."stack: "Error: EntitySetName not specified.\n    at Object.Create$1 (http://127.0.0.1:8000/Project1/Project1.js:3647:23)\n    at c.$create (http://127.0.0.1:8000/Project1/Project1.js:366:19)\n    at Object.DatabaseError (http://127.0.0.1:8000/Project1/Project1.js:80304:31)\n    at Object.CheckEntitySetName (http://127.0.0.1:8000/Project1/Project1.js:137379:46)\n    at Object.InitializeFieldDefinitions (http://127.0.0.1:8000/Project1/Project1.js:137428:12)\n    at Object.InternalInitFieldDefs (http://127.0.0.1:8000/Project1/Project1.js:137424:12)\n    at Object.InternalOpen (http://127.0.0.1:8000/Project1/Project1.js:124065:12)\n    at Object.DoInternalOpen (http://127.0.0.1:8000/Project1/Project1.js:77948:12)\n    at Object.OpenCursor (http://127.0.0.1:8000/Project1/Project1.js:78767:68)\n    at Object.SetActive (http://127.0.0.1:8000/Project1/Project1.js:78800:18)"[[Prototype]]: ObjectFMessage: "EntitySetName not specified."FStack: "Error: EntitySetName not specified.\n    at Object.Create$1 (http://127.0.0.1:8000/Project1/Project1.js:3647:23)\n    at c.$create (http://127.0.0.1:8000/Project1/Project1.js:366:19)\n    at Object.DatabaseError (http://127.0.0.1:8000/Project1/Project1.js:80304:31)\n    at Object.CheckEntitySetName (http://127.0.0.1:8000/Project1/Project1.js:137379:46)\n    at Object.InitializeFieldDefinitions (http://127.0.0.1:8000/Project1/Project1.js:137428:12)\n    at Object.InternalInitFieldDefs (http://127.0.0.1:8000/Project1/Project1.js:137424:12)\n    at Object.InternalOpen (http://127.0.0.1:8000/Project1/Project1.js:124065:12)\n    at Object.DoInternalOpen (http://127.0.0.1:8000/Project1/Project1.js:77948:12)\n    at Object.OpenCursor (http://127.0.0.1:8000/Project1/Project1.js:78767:68)\n    at Object.SetActive (http://127.0.0.1:8000/Project1/Project1.js:78800:18)"[[Prototype]]: Object$ancestor: {$ancestor: {…}, $class: {…}, $classname: 'Exception', $parent: {…}, $module: {…}, …}$class: {$ancestor: {…}, $class: {…}, $classname: 'EDatabaseError', $parent: {…}, $module: {…}, …}$classname: "EDatabaseError"$fullname: "DB.EDatabaseError"$module: {$name: 'DB', $intfuseslist: Array(6), $impluseslist: Array(2), $state: 5, $intfcode: ƒ, …}$name: "EDatabaseError"$parent: {$name: 'DB', $intfuseslist: Array(6), $impluseslist: Array(2), $state: 5, $intfcode: ƒ, …}$rtti: {name: 'EDatabaseError', $module: {…}, class: {…}, members: {…}, names: Array(0), …}[[Prototype]]: Object

Again, I am not sure of what to make of this error message as this same unit works on my current project.
I have attached the barebones project to this reply so you can see it more clearly.
I am flabbergasted as per why loading a JSON object into a dataset it's taking my sanity away. It should be as simple as assign, open, have data...
DatasetTest.zip (13.2 KB)

You have to define the persistent fields of the dataset in advance. Since this is a JSON being input manually, just create at design-time the fields you want in the dataset, like USER_ID, COMPANY_ID, etc.