How to make XDataWebDataSet open asynchronouos

I am using a derivative of the crud template.

xds_ is TXDataWebDataSet.
xwc_ is TXDataWebClient

This loads the entity

procedure Tfrm_Template_Edit.Load_Entity;
var
  LQry : string;
begin
  LQry := TCrudUtils.GetEntityGetQueryString
    (xds_.Connection.Model.DefaultSchema.FindEntityType (xds_.EntitySetName));
  xwc_Get_.Get (xds_.EntitySetName, LQry, FId);
end;

And first the event of TXDataWebClient.OnLoad, I have

  xds_.Close;
  xds_.SetJsonData (AId);
  xds_.Open;

The problem is that I need an asynchronous event to let me know when the data is loaded. If there isnt an event, if I use a timer, what state do I check ?

There are many ways to do so as described in the documentation, here:

You can use GetAsync, or use the OnLoad event of TXDataWebClient, or pass callback functions to the Get method.

Thanks.

I dont actually understand why this is this way in the generated crud template. Is it fetching a single record with ID=FID?

procedure Tfrm_Template_Edit.Load_Entity;
var
  LQry : string;
begin
  LQry := TCrudUtils.GetEntityGetQueryString
    (xds_.Connection.Model.DefaultSchema.FindEntityType (xds_.EntitySetName));
  xwc_Get_.Get (xds_.EntitySetName, LQry, FId);
end;

If so, why do I need this code to fetch the record again in the OnLoad event of the TXDataWebClient.

  xds_.Close;
  xds_.SetJsonData (AId);
  xds_.Open;

I really don't know what code are you talking about. The code you provided looks like it's yours code, I do think, for example, that TCrudUtils.GetEntityQueryString is your own code.

The code you are asking is usually a pattern where you use the TXDataWebClient to get the objects, then you set the objects to the dataset using SetJsonData so you can bind those objects to visual controls.

Hi Wagner, the code is from the TMS template. Its just heavily refactored. But it is the same. I refactored it so I can mass produce lots of forms, via form inheritance.

This is the unmodified version generated by the template. You will see both bits of code there. It was overwhelming when I started, some 8-10 months ago, so I had stuck to it. But refactored it into an inheritable form.

But that aside, I was asking what the two bits do, so I can understand what's happening.

unit View.aircraft.Edit;

interface

uses
  System.SysUtils, System.Classes, WEBLib.Graphics, WEBLib.Forms, WEBLib.Dialogs,
  Vcl.Controls, Vcl.StdCtrls, WEBLib.StdCtrls,

  Bcl.Rtti.Common, XData.Web.Client, Data.DB, WEBLib.CDS,
  WEBLib.DBCtrls, XData.Web.JsonDataset, XData.Web.Dataset, JS,

  App.Types, Crud.Utils, WEBLib.DB, WEBLib.Controls, WEBLib.ExtCtrls;

type
  TFViewaircraftEdit = class(TWebForm)
    pnlMessage: TWebPanel;
    lbMessage: TWebLabel;
    btCloseMessage: TWebButton;
    DataSource: TWebDatasource;
    btCancel: TWebButton;
    btSave: TWebButton;
    btDelete: TWebButton;
    lbRef: TWebLabel;
    edRef: TWebDBEdit;
    lbStatus: TWebLabel;
    edStatus: TWebDBEdit;
    lbIs_Helicopter: TWebLabel;
    edIs_Helicopter: TWebDBEdit;
    lbAircraft_Type: TWebLabel;
    edAircraft_Type: TWebDBEdit;
    lbRegistration: TWebLabel;
    edRegistration: TWebDBEdit;
    lbFuel_Capacity: TWebLabel;
    edFuel_Capacity: TWebDBEdit;
    lbLifting_Capacity: TWebLabel;
    edLifting_Capacity: TWebDBEdit;
    lbHours_Remaining: TWebLabel;
    edHours_Remaining: TWebDBEdit;
    lbTotal_Hours: TWebLabel;
    edTotal_Hours: TWebDBEdit;
    lbAs_Of: TWebLabel;
    edAs_Of: TWebDBEdit;
    lbNotes: TWebLabel;
    edNotes: TWebDBEdit;
    lbNotes_Popup: TWebLabel;
    edNotes_Popup: TWebDBEdit;
    lbCreated: TWebLabel;
    edCreated: TWebDBEdit;
    lbModified: TWebLabel;
    edModified: TWebDBEdit;
    lbCreated_By: TWebLabel;
    edCreated_By: TWebDBEdit;
    lbModified_By: TWebLabel;
    edModified_By: TWebDBEdit;
    XDataClientaircraftGet: TXDataWebClient;
    XDataClientaircraftDelete: TXDataWebClient;
    aircraftDataset: TXDataWebDataSet;
    aircraftDatasetRef: TLargeIntField;
    aircraftDatasetStatus: TStringField;
    aircraftDatasetIs_Helicopter: TIntegerField;
    aircraftDatasetAircraft_Type: TStringField;
    aircraftDatasetRegistration: TStringField;
    aircraftDatasetFuel_Capacity: TIntegerField;
    aircraftDatasetLifting_Capacity: TIntegerField;
    aircraftDatasetHours_Remaining: TFloatField;
    aircraftDatasetTotal_Hours: TFloatField;
    aircraftDatasetAs_Of: TDateTimeField;
    aircraftDatasetNotes: TStringField;
    aircraftDatasetNotes_Popup: TStringField;
    aircraftDatasetCreated: TDateTimeField;
    aircraftDatasetModified: TDateTimeField;
    aircraftDatasetCreated_By: TLargeIntField;
    aircraftDatasetModified_By: TLargeIntField;
    procedure btCloseMessageClick(Sender: TObject);
    procedure btCancelClick(Sender: TObject);
    procedure btSaveClick(Sender: TObject);
    procedure btDeleteClick(Sender: TObject);
    procedure XDataClientaircraftGetLoad(Response: TXDataClientResponse);
    procedure XDataClientaircraftDeleteLoad(Response: TXDataClientResponse);
    procedure XDataClientaircraftDeleteError(Error: TXDataClientError);
    procedure aircraftDatasetAfterApplyUpdates(Sender: TDataSet;
      Info: TResolveResults);
    procedure WebFormCreate(Sender: TObject);
  private
    FId: JSValue;
    FShowListProc: TListProc;
    procedure InsertEntity;
    procedure LoadEntity;
    procedure ShowNotification(Notification: string);
    procedure HiddenNotification;
    class function InternalCreateForm(AElementID: string;
      AShowListProc: TListProc; AInserting: Boolean; AId: JSValue): TWebForm; overload;
  protected
    FInserting: Boolean;
  public
    class function CreateForm(AElementID: string;
      AShowListProc: TListProc; AId: JSValue): TWebForm; overload;
  end;

var
  FViewaircraftEdit: TFViewaircraftEdit;

implementation

uses
  ConnectionModule;

{$R *.dfm}

{ TFViewaircraftEdit }

procedure TFViewaircraftEdit.btSaveClick(Sender: TObject);
begin
  if aircraftDataset.State in dsEditModes then
  begin
        aircraftDataset.Post;
    aircraftDataset.ApplyUpdates;
  end
  else
    FShowListProc;
end;

procedure TFViewaircraftEdit.btDeleteClick(Sender: TObject);
begin
  if aircraftDataset.State in dsEditModes then
    aircraftDataset.Post;
  XDataClientaircraftDelete.Delete(aircraftDataset.EntitySetName,
    TJSObject(aircraftDataset.CurrentData));
end;


class function TFViewaircraftEdit.CreateForm(AElementID: string;
  AShowListProc: TListProc; AId: JSValue): TWebForm;
var
  Inserting: Boolean;
begin
  Inserting := isNull(AId);
  Result := InternalCreateForm(AElementID, AShowListProc, Inserting, AId);
end;

procedure TFViewaircraftEdit.HiddenNotification;
begin
  pnlMessage.ElementHandle.hidden := True;
end;

procedure TFViewaircraftEdit.InsertEntity;
begin
  aircraftDataset.Close;
  aircraftDataset.SetJsonData('{}');
  aircraftDataset.Open;
  aircraftDataset.Insert;
end;

class function TFViewaircraftEdit.InternalCreateForm(AElementID: string;
  AShowListProc: TListProc; AInserting: Boolean; AId: JSValue): TWebForm;

  procedure AfterCreate (AForm: TObject);
  begin
    TFViewaircraftEdit(AForm).FInserting := AInserting;
    TFViewaircraftEdit(AForm).FId := AId;
    TFViewaircraftEdit(AForm).FShowListProc := AShowListProc;
    if AInserting then
      TFViewaircraftEdit(AForm).InsertEntity
    else
      TFViewaircraftEdit(AForm).LoadEntity;
    TFViewaircraftEdit(AForm).btDelete.Enabled := not AInserting;
  end;

begin
  Application.CreateForm(TFViewaircraftEdit, AElementID, Result, @AfterCreate);
end;

procedure TFViewaircraftEdit.LoadEntity;
var
  QueryString: string;
begin
  QueryString := TCrudUtils.GetEntityGetQueryString(
    aircraftDataset.Connection.Model.DefaultSchema.FindEntityType(
      aircraftDataset.EntitySetName
    )
  );
  XDataClientaircraftGet.Get(aircraftDataset.EntitySetName, QueryString, FId);
end;

procedure TFViewaircraftEdit.ShowNotification(Notification: string);
begin
  lbMessage.Caption := Notification;
  pnlMessage.ElementHandle.hidden := False;
end;

procedure TFViewaircraftEdit.btCloseMessageClick(Sender: TObject);
begin
  HiddenNotification;
end;

procedure TFViewaircraftEdit.WebFormCreate(Sender: TObject);
begin
  HiddenNotification;
end;

procedure TFViewaircraftEdit.XDataClientaircraftGetLoad(Response: TXDataClientResponse);
begin
  aircraftDataset.Close;
  aircraftDataset.SetJsonData(Response.Result);
  aircraftDataset.Open;
  
  aircraftDataset.Edit;  
end;

procedure TFViewaircraftEdit.XDataClientaircraftDeleteError(
  Error: TXDataClientError);
begin
  ShowNotification(Error.ErrorMessage);
end;

procedure TFViewaircraftEdit.XDataClientaircraftDeleteLoad(
  Response: TXDataClientResponse);
begin
  FShowListProc;
end;

procedure TFViewaircraftEdit.aircraftDatasetAfterApplyUpdates(Sender: TDataSet;
  Info: TResolveResults);
var
  I: integer;
  ResolveInfo: TResolveInfo;
begin
  for I := 0 to Length(Info.Records) - 1 do
  begin
    ResolveInfo := Info.Records[I];
//    if ResolveInfo.ResolveStatus = TResolveStatus.rsResolveFailed then
    if ResolveInfo.Error <> '' then
    begin
      ShowNotification(ResolveInfo.Error);
      Exit;
    end;
  end;
  FShowListProc;
end;

procedure TFViewaircraftEdit.btCancelClick(Sender: TObject);
begin
  FShowListProc;
end;

end.

This part requests the object from the server, asynchronously:

  XDataClientaircraftGet.Get(aircraftDataset.EntitySetName, QueryString, FId);

Then the OnLoad event is fired when the object is retrieved:

procedure TFViewaircraftEdit.XDataClientaircraftGetLoad(Response: TXDataClientResponse);
begin
  aircraftDataset.Close;
  aircraftDataset.SetJsonData(Response.Result);
  aircraftDataset.Open;
  
  aircraftDataset.Edit;  
end;

The above code gets the retrieved object (Response.Result) and "put" it in the dataset so its data can be bound to visual controls.