ServerAction does not run. Help me with a Step by Step, please.

I did some functions in javascript to access a DropBox URL and convert the content to Base64. When I use the JS component inside the "CLIENT ACTIONS", everything works fine.


However, I would like to run the script on the server side. When I add a "RUN SERVER ACTION" I can't get any feedback. Even an "alert ('TEST');" I can't run.


I am not yet familiar with the features of Outsystems. I'm a beginner. Could someone give me a very detailed step by step on how to make a javascript run using "RUN SERVER ACTION"?


Thanks in advance.

Hi Fabricio,

Server actions, hence the name run on the server, not in the browser.

For reactive web and mobile applications you should use the Javascript widget to execute javascript code in the browser.

For traditional web applications it is a bit different, see the following document: https://success.outsystems.com/Documentation/11/Extensibility_and_Integration/JavaScript/Extend_Your_Web_Application_Using_JavaScript/Define_and_Run_JavaScript_Code

Regards,

Daniel

Hi Fabricio,

In your Action flows, either in a Screen Action or a Server Action, you can use the RunJavaScript action of the HTTPRequestHandler extension to get your JavaScript code to run in the context of the browser.


However... Let me tell you that the RunJavaScript action does not RUN a JavaScript in the server! It only sends the JavaScript to the Browser. It is always the client (Browser) that runs the JavaScript, in a screen.


Hope it helps.

Rui Barradas

Thank you very much for the quick responses.


I still don't quite understand, I'm sorry.


1) See some screen. Can someone explain to me what is missing to perform some action with RunJavaScript?




2) Is it not advisable to run javascript on the server side? In my tests, on the client side everything went well. I would just like to transfer that same script to the server side and run it from time to time. Performing a "Run Server Action". It's possible? Is there a problem with this approach?

Hi Fabricio Diniz,


I'll like to share my observation and thoughts on this.

Traditional Web Application:

-  The Button widget possess a property called "Method", which can be set to any of these type - Submit, Ajax Submit and Navigate

- On introducing the RunJavaScript Server action node in the Button action flow, it got executed as expected. i.e. alert popup popped up with "Hello World!" message.


Reactive Web Application:

- The Button widget is not having any property called "Method"


- On introducing the RunJavaScript Server action node in the Button action flow, it didn't got executed as expected.

- So instead of that I used the Client Side JavaScript Node in the action flow and it got executed as required i.e. alert popup popped up with "Hello World!" message.

Conclusion: 

- Use Client-Side JS Node to execute any JavaScript statement(s) on the browser in case of Reactive Web Application.

- Use Server-Side RunJavaScript Node to execute any JavaScript statement(s) on the browser in case of Traditional Web Application. 


Thanks & Regards,

Benjith Sam Skariah :)

Thank you Sam Skariah.

I'm still having a hard time understanding these restrictions to execute javascritp on the "client action" and "serve action".

In the client I used a JS object. It executed my javascript perfectly. I wanted to see some screens teaching step by step how to create and execute a javascript in "Server Action" and get some feedback from the execution. With RUNJAVASSCRIPT I don't see any return. It doesn't seem to execute and nothing happens.

Hi Fabricio,


Like Benjith said, there are some differences between a Traditional Web Application and a Reactive Web Application.


In your case, you are using a Reactive Web Application, that's why the RunJavaScript server action didn't got executed as expected and it won't work. In this case, you need to use the JavaScript Node in your action (Client Side) flow and it will work as expected.


On the other hand, if you try to use the RunJavaScript server action in a Traditional Web Application, then it will work and you will see the result of the JavaScript code in your browser.


I'll leave this tutorial for you that explains the major differences between the Traditional Web and the Reactive Web applications:

https://www.youtube.com/watch?v=ZrPKWf7fnI8&feature=youtu.be


Keep in mind that you're using a Reactive Web Application for the next steps of your development plan :)


Hope it helps.

Rui Barradas


Right. With react web app, how can I make a timer run a javascript routine from time to time. It's possible? The timer only executes "Server Action". I don't have access to the JS Component.

Hi again Fabricio,


Unfortunately, Timers (in OutSystems) only run Server Side. That's why you don't have access to the JavaScript Node component. And Server Side Actions cannot run Client Side actions (only the opposite is possible).


But you can implement a timer client-side. In your case, you can implement that logic directly in your JavaScript script.

There are two JavaScript methods to control time intervals: setTimeout and setInterval.

You can check them here: https://www.w3schools.com/js/js_timing.asp


Why don't you use them to control the execution of your JavaScript routine? :)


Let me know if you managed to do it.

Rui Barradas

Rui,

I am very grateful for your help. I wish I could give back in some way. To the others who tried to help me, my thanks too.


Finally I begin to understand a little better. I did some tests in the 3 environments (mobile, web react app and web traditional) and managed to run some command in javascript in each environment.


I'm in doubt if javascript will be a good enough solution (it doesn't have to be the best one). Because I have several URLs of JPEG files on DropBox. At specific time intervals, I need to take the URLs of these images, convert them to BASE64 and send them to an external API. I made the javascript just to test to make this conversion and generate the content in BASE64. It worked perfectly in the Mobile environment, as "Client Action". Now I have to transfer this to "Server Action". I believe that I will use "Web Traditional" within Outsystems.


Any more suggestions? Do you think doing this routine via javascript is an acceptable path?

Rui,

Just to clarify a little more:

1) In any environment (web react or web traditional) is it possible to make this work with the Outsystems timer (see image below)? Or is the only way to run JavaScript at specific time intervals using JavaScript Timing Events? (setTimeout () and setInterval ())



2) Do you think that running javascript on the server side and with specific time intervals can cause performance and memory problems in the application?


Thanks!!!

Fabricio Diniz wrote:

Rui,

Just to clarify a little more:

1) In any environment (web react or web traditional) is it possible to make this work with the Outsystems timer (see image below)? Or is the only way to run JavaScript at specific time intervals using JavaScript Timing Events? (setTimeout () and setInterval ())



2) Do you think that running javascript on the server side and with specific time intervals can cause performance and memory problems in the application?


Thanks!!!

Hi Fabricio,

After reading this complete discussion I can see that you are having difficulty because you have your logic ready in JS and now you want to run it server side. But as everyone said this javascript is client side and can not be executed server side. In treditional web also if you add js it actually gets executed from screen when it is loaded in browser. So to run this logic server side you should convert you js code to server action logic.

Comming to your last two questions, below are my suggestions:

1) In any environment (web react or web traditional) is it possible to make this work with the Outsystems timer (see image below)? Or is the only way to run JavaScript at specific time intervals using JavaScript Timing Events? (setTimeout () and setInterval ())

My Answer: It is possible to execute your logic server side if you convert your js code to server side logic. setTimeout and setInterval won't work in timer.

2) Do you think that running javascript on the server side and with specific time intervals can cause performance and memory problems in the application?

My Answer: It will not execute so there is no point in talking about performance.


So I sould suggest you to convert your JS logic to a server action and then call it from timer. If you are still in doubt please share your JS code so that we cann suggest here how you can convert it to a server action.


Hi Nikhil Gaur,


Below, the functions (javascript) I use to convert a JPEG image from a URL to a local variable in BASE64. Works well in "Client Action". How to convert this code from the point of view of a "Server Action" to run inside a timer in Outsystems?


//função para pegar uma imagem dentro de um DOCUMENT e converter para BASE64

//------------------

function getBase64Image(img) {

var canvas = document.createElement("canvas");

canvas.width = img.naturalWidth //img.width;

canvas.height = img.naturalHeight;

var ctx = canvas.getContext("2d");

ctx.drawImage(img, 0, 0);

//qualidade da imagem: 0.0 até 1.0 (0.8=80%)

var dataURL = canvas.toDataURL("image/jpeg", 0.8); //tipo da IMAGEM JPG

//CONVERTE a IMG do documento para BASE64 e retorna pela FUNÇÃO

return dataURL;

}

//------------------

//------------------

//Obtem a imagem da URL passada e converte para BASE64

//------------------

function obterImagemDaUrl(uri) {

var imgDropBox = document.createElement("img");

imgDropBox.crossOrigin = 'anonymous'; //<-- set here

//FUNÇÃO que sera executada ao carregar a imagem (OnLoad)

//------------------

imgDropBox.onload = function(){

//Passa a variável IMG do DOCUMENT para ser convertida para BASE64

var base64 = getBase64Image(document.getElementById("imageid"));

//Passa a variável BASE64 para o ambiente OUTSYSTEMS: imageDropBrox

$parameters.imageDropBox = base64;

console.log(base64); //escreve conteúdo no console - *para teste*

}

//------------------

//------------------

//Identifica a IMG no DOCUMENT

imgDropBox.name="imageid";

imgDropBox.id="imageid";

imgDropBox.src = uri; //informa URL passada como parametro para baixar

//------------------

document.body.appendChild(imgDropBox); //baixa a imagem para o DOCUMENT

}


Thanks.

Solution

Hi Fabricio,

You can use GetRequest_Submit action from HTTPRequestHandler extension. It is system extension so available without adding any extra forge. In this action you can pass your image URL and in return you will get its type and base64 string of the image.

So you just have to create a server action and call this GetRequest_Submit in it. In your timer you know what you have to do, just call this newly created server action.

Solution

Nikhil Gaur, cool!


I believe it would be almost the way I need it. However, the GETRequest_Submit returns the binary content to the BinaryContent variable, but it is not in the format I need. Which is BASE64:

Like this example, Hello World on Base64: "T2zDoSwgbXVuZG8h"


1) Would GETRequest_Submit do this conversion itself? How?


2) Or would I have to use the BinaryContent variable to do the conversion in another way? Using JavaScript, as you may have seen in the code above, I had the getBase64Image function that returned me exactly with the string I need to use.


Thanks a lot for the help!


Nikhil Gaur,

I found a BynaryToBase64 module, I believe that I should be able to do the conversions through it.

It seems to me that is it then. You must attend to what I needed.

As I understand it I should only use JavaScript on the client side. On the server side, if necessary, I'll see how the code extension works with C #.

Thank you all for the explanations. All the answers helped me in some way.

Hi again Fabricio,


I read the rest of the discussion. It is nice that you are almost done :)


Responding to your questions:

1) The GETRequest_Submit action returns two different variables: BinaryContent and TextContent. The variable TextContent is already a Base64 String, so you don't need any extra conversion.
If you need for the future, you have an extension called BinaryData, that provides actions to manipulate BinaryData contents. In there, you will find 2 Server Actions: BinaryToBase64 and Base64ToBinary. You can use them to do the conversions, but in this case you don't need it.


2) Since you are running your code Server Side right now, you don't need to do the conversion Client Side. Like I said, the variable TextContent is already a Base64 String, so you can just use it.


Let me know if you managed to do it.

Rui Barradas

Rui Barradas wrote:

Hi again Fabricio,


I read the rest of the discussion. It is nice that you are almost done :)


Responding to your questions:

1) The GETRequest_Submit action returns two different variables: BinaryContent and TextContent. The variable TextContent is already a Base64 String, so you don't need any extra conversion.
If you need for the future, you have an extension called BinaryData, that provides actions to manipulate BinaryData contents. In there, you will find 2 Server Actions: BinaryToBase64 and Base64ToBinary. You can use them to do the conversions, but in this case you don't need it.


2) Since you are running your code Server Side right now, you don't need to do the conversion Client Side. Like I said, the variable TextContent is already a Base64 String, so you can just use it.


Let me know if you managed to do it.

Rui Barradas

Grateful for the attention Rui.

It worked the way I needed it. Special thanks to Nikhil Gaur!

Thanks guys!


You're welcome Fabricio, glad we could help.