Transfer from CAPI Webview to logic

Discussions about CSEntry
Forum rules
New release: CSPro 8.0
htuser
Posts: 631
Joined: December 19th, 2011, 6:26 pm
Location: Silver Spring Area, MD, USA

Transfer from CAPI Webview to logic

Post by htuser »

Dear CSPro Developer Team,
I already discussed this request with Alex months ago. He advised me a way on which i find a severe issue.
What's the need?
Sometimes we would perform some operations, calculations (not possible with CSPro logic functions) using some javascript libraries and transfer results to CSPro logic. Right now, it's possible with HTMLDialog, but this require to open a HTML page and come back to CSEntry. However, sometimes, we would like to perform theses calculations/operations in the background. And, since we always have an active webview displaying CAPI, i'm asking myself if i can't run javascript inside it and retrieve results to CSPro logic. Alex advised me to display a HTML pages with nothing (no UI) in the body part but only javascript codes.

Code: Select all

<!doctype html>
<html lang="en">
<head>
    <script>
        //Calling javascript and closing dialog on callback
       </script>
</head>
<body>
    <!--Nothing here-->
</body>
</html>
But, the issue with this way: if there's an error in the javascript code, we can't close this pretty small, nearly invisible window...And we're obliged to close CSEntry...
So, i'm asking if you don't have any workaround for using the CAPI Webview part to run Javascript and transfert results in logic?
Note that, in the help, i can read
JavaScript Interface
A JavaScript interface exists to facilitate the invocation of user-defined functions from question text. This feature allows advanced users to take advantage of the power of JavaScript to allow some interaction between question text and CSPro logic.


But, i can't find more explanations on if it's possible of using the CAPI part for my need.

Thanks in advance for your support!
G.VOLNY, a CSProuser from Haiti, since 2004
alex_izm
Posts: 19
Joined: December 9th, 2016, 11:31 am

Re: Transfer from CAPI Webview to logic

Post by alex_izm »

Yes, it is possible to run JavaScript code from within the QSF text. Try the following:

In your application PROC GLOBAL add this function:

Code: Select all

function showErrorMessage()
  errmsg("This message was called from JavaScript embedded in the QSF text");
end;
Then in one of the questions CAPI text switch to code (</>) and copy/paste the following:

Code: Select all

<script>
    CSPro.runLogicAsync('showErrorMessage();', "");
</script>
<div>
  This example executes CSPro.logic() call as soon as this question gets focus
</div>
Upon navigation to this question you should see the message.

Note that the jQuery library is not referenced by the CAPI text document, so only pure JavaScript will work.

Alex
htuser
Posts: 631
Joined: December 19th, 2011, 6:26 pm
Location: Silver Spring Area, MD, USA

Re: Transfer from CAPI Webview to logic

Post by htuser »

Thanks Alex for your support.
The description you provide is more concerning running a CSPro logic function inside Javascript in the CAPI text webview. No great interest since i can write CSPro logic function directly in this part.
Here's a real example illustrated my request: Bearing calculation between two coordinates. https://stackoverflow.com/questions/360 ... to-another
Normally i can write this in the CAPI part:

Code: Select all

function angleFromCoordinate(lat1,lon1,lat2,lon2) {
    var p1 = {
        x: lat1,
        y: lon1
    };

    var p2 = {
        x: lat2,
        y: lon2
    };
    // angle in radians
    var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
    // angle in degrees
    var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;

   // document.getElementById('rotation').innerHTML ="Rotation : "+ angleDeg;
    return angleDeg;
    
}
Assuming that i've theses items in CSPro;
Latitude_1, Longitude_1, Latitude_2, Longitude_2;

a) Please how (what's the exact syntaxis) to call them in the javascript function

Code: Select all

 angleFromCoordinate()
; ?
With HTMLDialog, i would pass them as a string or json and parse them in javascript.
If i find a way to pass CSPro items in the function *for example put them in function and affect them to javascript var using cspro.runlogic/cspro.runlogicasync, please,
b) how to return the value of the

Code: Select all

 angleFromCoordinate()
to CSPro logic?

Thanks in advance for your help!
G.VOLNY, a CSProuser from Haiti, since 2004
alex_izm
Posts: 19
Joined: December 9th, 2016, 11:31 am

Re: Transfer from CAPI Webview to logic

Post by alex_izm »

Getting values from CSpro to JS and returning values from JS to CSpro can be achieved with function parameters. In your particular example we can do the following:

In your CSpro code you would declare two functions like this:

Code: Select all

function string getCoordinatesJson()
  exit maketext('{ "lat1": %f, "lon1": %f, "lat2": %f, "lon2": %f}',
    Latitude_1,
    Longitude_1,
    Latitude_2,
    Longitude_2
  );
end;

function setAngle(string angle)
  numeric angleN = tonumber(angle);
  
  //do what you need to do with angleN here
  //...
  errmsg("My angle is %f", angleN);
end;
The first function getCoordinatesJson() is used to "bus" the input values to JavaScript layer. Second function setAngle() is used to retrieve result from JS to CSpro.

Then your JavaScript code in your CAPI text will look like this:

Code: Select all

<script>
   function angleFromCoordinate(lat1,lon1,lat2,lon2) {
        var p1 = {
            x: lat1,
            y: lon1
        };

        var p2 = {
            x: lat2,
            y: lon2
        };
        // angle in radians
        var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
        // angle in degrees
        var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;

        // document.getElementById('rotation').innerHTML ="Rotation : "+ angleDeg;
        return angleDeg;

    }
  
    //getting input from CSPro variables
    var coords = JSON.parse(CSPro.runLogic('getCoordinatesJson();'));
  
    //calling angleFromCoordinate() function
    var angle = angleFromCoordinate(coords.lat1, coords.lon1, coords.lat2, coords.lon2);
  
    //returning result to CSPro
    CSPro.runLogicAsync(`setAngle('${angle}');`, "");
</script>
Hope this helps.
Alex
htuser
Posts: 631
Joined: December 19th, 2011, 6:26 pm
Location: Silver Spring Area, MD, USA

Re: Transfer from CAPI Webview to logic

Post by htuser »

Thanks a lot Alex. This solve the issue we discussed last october.
I haven't imagined we can use theses CSPro-Javascript API functions in the CAPI part.
Right now, we're free to run any javascript codes.
A last question, does it possible to include any javascript libraries in the CAPI part?
Best,
G.VOLNY, a CSProuser from Haiti, since 2004
alex_izm
Posts: 19
Joined: December 9th, 2016, 11:31 am

Re: Transfer from CAPI Webview to logic

Post by alex_izm »

Yes, it is possible to include external scripts and CSS links in CAPI text. Just declare them as you would normally at the top of your CAPI HTML. This example here adds links to jQuery and Bootstrap libraries included in CSPro distribution:

Code: Select all

<link rel="stylesheet" href="/external/bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="/external/bootstrap/bootstrap-icons.css">
<link rel="stylesheet" href="/css/dialogs.css">

<script src="/external/jquery/jquery.min.js"></script>
<script src="/external/bootstrap/bootstrap.bundle.min.js"></script>
<script src="/external/mustache/mustache.min.js"></script>
You can similarly include your own custom JS and CSS files. the source URL is relative to your application path. So, for example if you have file MyLib.js located in the same folder as your application, then the link should be declared like this:

Code: Select all

<script src="MyLib.js"></script>
Alex
htuser
Posts: 631
Joined: December 19th, 2011, 6:26 pm
Location: Silver Spring Area, MD, USA

Re: Transfer from CAPI Webview to logic

Post by htuser »

Thanks a lot Alex,
This solved a long ago request and right now, we will have the greatest control on CSEntry Apps.

However, if we can have a way to add JS files as an external logic file, this will be cleanest so we'll not obliged to write

Code: Select all

<script src="MyLib.js"></script>
for any CAPI text part, for each items/questions. I don' t know how complicated it's to have this.

Other, i've a difficulty to find the right syntaxes for passing a JS argument to CSPro.invokeAsync or CSPro.runLogicAsync.
The HTML code is:

Code: Select all

  <!-- Firstname and Lastname -->
        <div class="horizontal-group">
          <div class="form-group left">
            <label for="Prenom" class="label-title">Prenom *</label>
            <input type="text" id="Prenom" class="form-input" placeholder="Saisi votre prenom"  onblur="ValidateFirstName('Prenom')" />
          </div>
          <div class="form-group right">
            <label for="Nom" class="label-title">Nom</label>
            <input type="text" id="Nom"  class="form-input" placeholder="Saisi votre Nom" />
          </div>
        </div>
		
The CSPro function is:
Function string ValidationPrenom (string Prenom)
    if length(strip(Prenom)) in 0:3 then
        errmsg
("Ce nom,%s,est invalide! SVP veuillez corriger!",Prenom);
            endif;
    end;
The string of the argument come from this :

Code: Select all

var result =document.getElementById(inputId).value;
It display a string.
I transform it to a Javascript object:

Code: Select all

var arguments = {result};
I pass it to a CSPro function

Code: Select all

CSPro.invokeAsync("ValidationPrenom", JSON.stringify(arguments)); 
It doesn't work...
I also try directly the ID tag and don't rung...

Code: Select all

CSPro.runLogicAsync(`ValidationPrenom(${$('#Prenom').val()});`);
The JS function is:

Code: Select all

function ValidateFirstName(inputId) { 
    var result =document.getElementById(inputId).value;
	var arguments = {result}; 
//var test2=JSON.parse(result).	
		//alert (result);
		//alert (arguments); 
//alert (test2); 
	//alert(JSON.stringify(arguments.result));
	//CSPro.invokeAsync("ValidationPrenom", JSON.stringify(arguments));
	CSPro.runLogicAsync(`ValidationPrenom(${$('#Prenom').val()});`); 
    }

i can post a demo app for more clarifications.

Best,
G.VOLNY, a CSProuser from Haiti, since 2004
alex_izm
Posts: 19
Joined: December 9th, 2016, 11:31 am

Re: Transfer from CAPI Webview to logic

Post by alex_izm »

Your code looks fine. There was only one issue. Your argument to the ValidatePrenom() function is a string, so you need to enclose it in single or double quotes. Here is complete working HTML:

Code: Select all

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="/external/bootstrap/bootstrap.min.css">

<script src="/external/jquery/jquery.min.js"></script>
<script src="/external/bootstrap/bootstrap.bundle.min.js"></script>

<script>
  function ValidateFirstName(inputId) { 
	CSPro.runLogicAsync(`ValidationPrenom("${$('#Prenom').val()}");`); 
  }
</script>

<!-- Firstname and Lastname -->
<div class="horizontal-group">
  <div class="form-group left">
    <label for="Prenom" class="label-title">Prenom *</label>
    <input type="text" id="Prenom" class="form-input" placeholder="Saisi votre prenom" onblur="ValidateFirstName('Prenom')">
  </div>
  <div class="form-group right">
    <label for="Nom" class="label-title">Nom</label>
    <input type="text" id="Nom" class="form-input" placeholder="Saisi votre Nom">
  </div>
</div>
htuser
Posts: 631
Joined: December 19th, 2011, 6:26 pm
Location: Silver Spring Area, MD, USA

Re: Transfer from CAPI Webview to logic

Post by htuser »

Thanks a lot Alex. This give me a clearest view about the right syntax.
However, it failed and i can see this message in the console
Uncaught ReferenceError: $ is not defined
at ValidateFirstName (.CS0.html:136:22)
My first idea was to pass the argument from the result

Code: Select all

document.getElementById(inputId).value;
Since i think it's a more dynamic way.
Please, what's the exact syntax for passing any Javascript Var as an argument to both, CSPro.invokeAsync or CSPro.runLogicAsync?
For CSPro.invokeAsync , i also tried:

Code: Select all

var result =document.getElementById(inputId).value;
var arguments = {result}; 
CSPro.invokeAsync("ValidationPrenom", JSON.stringify(arguments.result));
It doesn't work...
It's possible to have

Code: Select all

CSPro.runLogicAsync(`ValidationPrenom("${$('result')}");`); 
Or something different?

Best,
G.VOLNY, a CSProuser from Haiti, since 2004
alex_izm
Posts: 19
Joined: December 9th, 2016, 11:31 am

Re: Transfer from CAPI Webview to logic

Post by alex_izm »

$ function is defined in a jQuery library. Have you linked it at the top of your HTML?
Post Reply