#1 2018-10-15 12:36:19

Ehab
Member
Registered: 2016-09-07
Posts: 15

Translate service to Javascript

I reuse some Javascript code from Javascript authentication . Thanks for Ab, esmondb and RangerX.
I added more functions to mORMotClient in order to consume Interface based services. I will share it when done. But I still have one point and I need some help.
For example if I have an interface like this

  IAccountsChart = interface(IBaseFactory)
    ['{A35B2E70-C92D-4573-B46C-83F971B7E3DF}']
    function GetChartData(out Items: TAccChartItems ): Integer;
    function InsertChartItem(out Items: TAccChartItems; ParentId: TId; Index : Integer): Integer;
    function DelChartItem(out Items: TAccChartItems; ItemId: TId): Integer;
    function MoveChartItem(out Items: TAccChartItems; ItemId, ParentId : TId; Index : Integer=-1): Integer;
    function UpdateChartItem(Item: TAccChartItemData): Integer;
  end;

I want to produce the following Javascript code for this interface so I can reflect new added functions to Javascript.

function AccountsChart(mORMotClient){
  this.onGetChartData= null;
  this.onInsertChartItem= null;
  this.onDelChartItem= null;
  this.onMoveChartItem= null;
  this.onUpdateChartItem= null;

  ........................
  
  this.GetChartData = function(){
    return doCall('GetChartData', null, this.onGetChartData);
  }
  this.InsertChartItem = function(Parent, Index){
    return doCall('InsertChartItem', Parent, Index, this.onInsertChartItem);
  }
  this.DelChartItem = function(ItemId){
    return doCall('DelChartItem', ItemId, this.onDelChartItem);
  }
  this.MoveChartItem = function(ItemId,Parent, Index){
    return doCall('MoveChartItem', ItemId,Parent, Index, this.onMoveChartItem);
  }
  this.UpdateChartItem = function(Item){
    return doCall('UpdateChartItem', Item, this.onUpdateChartItem);
  }
}

can I generate that Javascript at my mORMot server?
I want to call it directly from the browser like that :

<script src="http://localhost:888/root/GetJScript/AccountsChart"></script>
<script>
......................
  var accountsChart=New AccountsChart(mORMotClient);
  var chartData = accountsChart.GetChartData();
......................
</script>

Last edited by Ehab (2018-10-15 13:10:47)

Offline

#2 2018-10-15 13:19:48

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Translate service to Javascript

It may be possible if you write the proper Mustache template.
See https://synopse.info/files/html/Synopse … #TITLE_482

Offline

#3 2018-10-16 09:55:48

Ehab
Member
Registered: 2016-09-07
Posts: 15

Re: Translate service to Javascript

Thanks ab for your quick response and pointing me to Mustache template.
I used a Mustache template and I got some results very close to what I need.
My problem now is I want a comma (,) not semicolon (;) in function parameters like the following

function GetChartBranchData(  Items;    ItemId    );

//I wanted it to be
//function GetChartBranchData(  Items,    ItemId    );

Can I use something else  instead of {{commaArg}} to produce a comma (,) not semicolon (;)?

This is the  template :

{{<method}}function {{methodName}}({{#args}} {{^dirResult}} {{argName}}{{commaArg}}{{/dirResult}} {{/args}} );{{/method}}
{{<member}}this.on{{methodName}} = null;{{/member}}
  {{#orm}}
  {{^isInMormotPas}}
  {{/isInMormotPas}}
  {{/orm}}
  {{#soa.services}}
  /* Definition of {{interfaceURI}} Object */
  // ------------------------------------
  function {{interfaceURI}}(mORMotClient){
    this.initialized=false;
    this.mORMotClient=mORMotClient;  
{{#methods}}
    {{>member}}
{{/methods}}

    var doCall = function(fnName, fnParam, callBack){
      funcName  = '{{interfaceURI}}.' + fnName;
      funcParam = '[' + ((! fnParam) ? '' : JSON.stringify(fnParam)) + ']';
      return mORMotClient.callFunc(funcName, funcParam, callBack, this);
    }

    this.Initialize = function(){
      doCall('_contract_', null, this.onInitialize);
    }

    this.onInitialize = function(req){
      var data = req.responce;
      if(data.error.errorNo == 0)
	req.owner.initialized = true;
    }
	
{{#methods}}
    {{>method}}
{{/methods}}
 }

  {{/soa.services}}

The result of this template is

  /* Definition of AccountsChart Object */
  // ------------------------------------
  function AccountsChart(mORMotClient){
    this.initialized=false;
    this.mORMotClient=mORMotClient;  
    this.onExportJScript=null;
    this.onFillDefaultChartData=null;
    this.onGetChartData=null;
    this.onGetChartBranchData=null;
    this.onInsertChartItem=null;
    this.onAddChartItem=null;
    this.onDelChartItem=null;
    this.onMoveChartItem=null;
    this.onUpdateChartItem=null;
    this.onGetChartItem=null;
    this.onChangeChartItemKind=null;

    var doCall = function(fnName, fnParam, callBack){
      funcName  = 'AccountsChart.' + fnName;
      var fnParams = [];
      for(var i=0; i < fnParam.length; i++) fnParams[i] = fnParam[i];
      return mORMotClient.callFunc(funcName, JSON.stringify(fnParams), callBack, this);
    }

    this.Initialize = function(){
      doCall('_contract_', null, this.onInitialize);
    }

    this.onInitialize = function(req){
      var data = req.responce;
      if(data.error.errorNo == 0)
	req.owner.initialized = true;
    }
	
    this.ExportJScript= function (   ){
      return doCall('ExportJScript', arguments, this.onExportJScript);
    };
    this.FillDefaultChartData= function (  Items;    ChartType    ){
      return doCall('FillDefaultChartData', arguments, this.onFillDefaultChartData);
    };
    this.GetChartData= function (  Items    ){
      return doCall('GetChartData', arguments, this.onGetChartData);
    };
    this.GetChartBranchData= function (  Items;    ItemId    ){
      return doCall('GetChartBranchData', arguments, this.onGetChartBranchData);
    };
    this.InsertChartItem= function (  Items;    ParentId;    Index    ){
      return doCall('InsertChartItem', arguments, this.onInsertChartItem);
    };
    this.AddChartItem= function (  Items;    ParentId    ){
      return doCall('AddChartItem', arguments, this.onAddChartItem);
    };
    this.DelChartItem= function (  Items;    ItemId    ){
      return doCall('DelChartItem', arguments, this.onDelChartItem);
    };
    this.MoveChartItem= function (  Items;    ItemId;    ParentId;    Index    ){
      return doCall('MoveChartItem', arguments, this.onMoveChartItem);
    };
    this.UpdateChartItem= function (  Item    ){
      return doCall('UpdateChartItem', arguments, this.onUpdateChartItem);
    };
    this.GetChartItem= function (  Item;    ItemId    ){
      return doCall('GetChartItem', arguments, this.onGetChartItem);
    };
    this.ChangeChartItemKind= function (  ItemId;    ItemKind    ){
      return doCall('ChangeChartItemKind', arguments, this.onChangeChartItemKind);
    };
 }

Offline

#4 2018-10-16 12:21:09

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Translate service to Javascript

Did you try

{{#commaArg}}, {{/commaArg}}

?

Offline

#5 2018-10-16 12:43:48

Ehab
Member
Registered: 2016-09-07
Posts: 15

Re: Translate service to Javascript

Thanks ab
It works now after using

{{#commaArg}}, {{/commaArg}}

My template file name is "Js.pas.mustache" and I can call it from Javascript like this:

  <script src='http://localhost:888/root/wrapper/Js/mORMotClient.pas.txt'></script>

But I want to call it like this

  <script src='http://localhost:888/root/js/mORMotClient_Services.js'></script>
Or
  <script src='http://localhost:888/root/js/Services.js'></script>

Can you please point me to a solution to change
wrapper/Js/mORMotClient.pas.txt
to
js/mORMotClient_Services.js
?

Last edited by Ehab (2018-10-16 12:46:24)

Offline

#6 2018-10-16 12:49:01

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Translate service to Javascript

I would tend to use a mORMot-based service for this, with an in-memory cache of the js content.
Just re-use the content of procedure WrapperMethod() for your own method.

If you call the method js(Ctxt), then you will be able to parse what is after the root/js/.... method name from the Ctxt.URIAfterRoot value.

Offline

#7 2018-10-17 02:04:54

Ehab
Member
Registered: 2016-09-07
Posts: 15

Re: Translate service to Javascript

Hi ab
I am new to mORMot.

ab wrote:

I would tend to use a mORMot-based service for this, with an in-memory cache of the js content.
Just re-use the content of procedure WrapperMethod() for your own method.

I didn't know what do you mean by "in-memory cache" and how to do that in mORMot, but I get that you advice me to save the content and reuse it. So I saved the js content to a file "Service.js". I did this  at server start so I can get the file later when a client need it at anytime. I used something like this:

  JsName := ExtractFileName(aJsFileName);
  Content:= WrapperFromModel(aServer, StringFromFile(aMustacheTemplate), JsName , 888);
  FileFromString(Content, aJsFileName);
ab wrote:

If you call the method js(Ctxt), then you will be able to parse what is after the root/js/.... method name from the Ctxt.URIAfterRoot value.

I'm using something like sample 09 - HttpApi web server to access the file from Javascript like this:

<script src="http://localhost:888/root/js/Services.js"></script>

This is enough for my learning purpose right now, but it is still advisable to learn from you and other mORMot experts. I want to share a full working sample (Server, Delphi client, web client and MySql database). I hope this may save some time for other newbie like me. I know the rules No long code in the forum. Can I upload it to my website and put the download link here?

There is another thing I need to do and I need your help to point me to the right direction as usual. smile

Delphi :
  function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;

Output Javascript :
  function GetChartBranchData(Items, ItemId)

I want to remove the out parameter(s) Items in this case. I don't want to confuse the Javascript programmer.
I want it to be like this:

Delphi :
  function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;

Output Javascript:
  function GetChartBranchData(ItemId)

Last edited by Ehab (2018-10-17 02:27:49)

Offline

#8 2018-10-17 10:27:14

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Translate service to Javascript

Yes, of course, you can upload it to your website, or you could even make a pull request on GitHub, adding a new folder in the "third party" samples.

For the output/results parameters in javascript, I guess the most obvious could be to return an object with the output fields: {Items:[...],Result:1234}

Offline

#9 2018-10-18 16:37:16

Ehab
Member
Registered: 2016-09-07
Posts: 15

Re: Translate service to Javascript

Hi ab,

ab wrote:

For the output/results parameters in javascript, I guess the most obvious could be to return an object with the output fields: {Items:[...],Result:1234}

My last question was about the output of Mustache template not javascript.
I don't want the Delphi method parameters of kind output to be appear in Mustache template output.

For example if I have the following interface:

  IAccountsChart = interface(IBaseFactory)
    ['{A35B2E70-C92D-4573-B46C-83F971B7E3DF}']
    function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;
  end;

And I use the following template fragment for output method's name and parameter

{{<method}}this.{{methodName}}=function({{#args}}{{^dirResult}}{{argName}}{{#commaArg}}, {{/commaArg}}{{/dirResult}}{{/args}}){
      .......................................
    }{{/method}}

Mustache template output is :

  this.GetChartBranchData = function(Items, ItemId){
   .......................................
  }

But I want the template to output:

  this.GetChartBranchData = function(ItemId){
   .......................................
  }

Is that possible ?

Offline

#10 2018-10-20 04:21:28

Ehab
Member
Registered: 2016-09-07
Posts: 15

Re: Translate service to Javascript

Hi ab,
I have abandoned using the Mustache template. I used TSQLRestServerDB.Services to get the output I want.
I uploaded a sample at gulf-soft.com/e/files/Mormot_Sample.zip
In this sample I included my thought about making it easier for JavaScript programmer for consuming my services. Beside other things like simple Http server and using MySql.

Now if I have Interface like this:

  IClientRepository = interface(IBaseFactory)
    ['{31D143DB-9EED-4C00-940B-52C9BDB515D1}'] 
    function GetClient(Id : TId; out aClient: TSQLClient) : Cardinal;
    function SaveClient(var aClient: TSQLClient) : Cardinal	;
..............................
  end;

In JavaScript I will use some code like this:

  var clientRepository = new ClientRepository(_mc);
  var r = clientRepository.GetClient(Id);
  if(r.XHR.status == 200){
	workClient = r.responce.result[0];
	displayClent(workClient);
  }
  else
     alert(r.XHR.responseText);  

I hope this sample helps others and I get some comments to improve my knowledge in mORMot.

Last edited by Ehab (2018-10-20 04:30:27)

Offline

Board footer

Powered by FluxBB