Page 1 of 2
Transfer from CAPI Webview to logic
Posted: January 20th, 2022, 6:23 am
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!
Re: Transfer from CAPI Webview to logic
Posted: January 20th, 2022, 3:38 pm
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
Re: Transfer from CAPI Webview to logic
Posted: January 20th, 2022, 4:18 pm
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
; ?
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
to CSPro logic?
Thanks in advance for your help!
Re: Transfer from CAPI Webview to logic
Posted: January 21st, 2022, 10:06 am
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
Re: Transfer from CAPI Webview to logic
Posted: January 21st, 2022, 2:35 pm
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,
Re: Transfer from CAPI Webview to logic
Posted: January 23rd, 2022, 1:59 pm
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:
Alex
Re: Transfer from CAPI Webview to logic
Posted: January 25th, 2022, 12:56 pm
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
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:
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,
Re: Transfer from CAPI Webview to logic
Posted: January 25th, 2022, 1:43 pm
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>
Re: Transfer from CAPI Webview to logic
Posted: January 25th, 2022, 2:18 pm
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,
Re: Transfer from CAPI Webview to logic
Posted: January 26th, 2022, 11:32 am
by alex_izm
$ function is defined in a jQuery library. Have you linked it at the top of your HTML?