Interaction between the 1C Platform and JavaScript

Alexander Biryukov

19.01.2023 16 min

1C- Java.png

 

Let us step back from designing trade and warehousing systems and consider this. While the 1C:Enterprise platform is a powerful and flexible framework for creating accounting applications, it is possible to expand its functionality even more by running various scripts written in other languages directly in 1C applications.

An immediate idea of how to implement it is to use commands RunApp() and System().

Here is an example with the first command:

RunApp("MyExcelFile.xls");

This command first starts the Excel application (or another application associated with .XLS files) and then opens the file in this application.

Perfect. But what if we need to get a response from a running application and process this response in 1C?

Here is how we can do it using the second command:

System("udevadm info --query=all --name=/dev/sda | grep ID_SERIAL_SHORT >> temp.txt");

textReader = New TextReader;

textReader.Open("/home/username/temp.txt");

line = textReader.ReadLine();

While line <> Undefined Do

EndDo;

If we run this code in Linux, first, the application saves to a temp.txt file the information about hard drives connected in the system, and then 1C:Enterprise platform reads this file, thus making it possible to process the result correctly.

The algorithm is that we launch an application, it writes the result to a file, and then we read the result recorded in it. Not quite efficient, right? 

Maybe there is a way to run an application written in another language directly inside the platform and exchange data directly between the platform and this application? The answer is yes, absolutely.

Let me describe one of the possible options to implement such an interaction.

Well, where do we start? To begin with, let us talk about how we can launch other applications inside the platform. Above, we considered two simple launch options, but our aim here is not just to run and forget. Instead, we want to retrieve the result and process it. Ideally, we want to exchange data between a 1C and a third-party application. What can we do? What should we use?

Here, a control called HTMLDocumentField comes to our aid. It is a special-purpose control that allows viewing HTML documents.

In fact, this is a web browser built into the 1C:Enterprise platform. Its advantage for us is that this control is actually a "mini-browser" capable of running scripts written in JavaScript. Just the way the "big" ones do! As for JavaScript language, I can hardly imagine it needs an introduction to any developer who is at least familiar with the web.

I suggest we create some simple examples to demonstrate the interaction of the 1C:Enterprise platform and scripts written in the JS. And closer to the end of this article, we will talk about why it can be helpful.

Let's go!

Open Designer. Create a new external data processor, and add a form and a template to it:

pic_1.png

When creating the template, set its type to Text Document:

pic_2.png

Here we want to store a pre-made template for a simple web page:

pic_3.png

Now we open the previously created form and create an HTML form attribute of type String:

pic_4.png

Put this attribute in the form, and assign type HTML Document Field to it:

pic_5.png

As a result, the form will look like this:

pic_6.png

And it is precisely in this control where all the magic happens. But let us continue.

Add the following command to the form:

pic_7.png 

And place the following code in the button click handler: 

&AtClient

Procedure Initialize(Command)

            HTML = GetTemplate("TemplateHTML");

            ourDIV = Items.HTML.Document.getElementById("ourDIV1");

            ourDIV.setAttribute("onclick", "alert('Hello from JavaScript');");

EndProcedure

                                            

&AtServer

Function GetTemplate(templateName)

           

            DataProcessor = FormAttributeToValue("Object");

            Return DataProcessor.GetTemplate(templateName).GetText();

           

EndFunction

What happens when we run this code? In procedure Initialize(), we first get the page previously saved into the HTML template, then using Id = "ourDIV1" we look for an element on this page, and, finally, we set attribute onclick for this element. With this, clicking on element ourDIV should bring up a window with message "Hello from JavaScript."

Let us put this code to the test and see how it works. Start the platform in dialog mode, open our data processor, and press button Initialize. Then click on element DIV1. If we do everything correctly, here is what we get:

pic_8.png

Cool! We were able to change the web page source code and managed to get the JS script output directly inside the platform.

Let us continue and try to answer the question of whether it is possible to call a JS function from 1C.

The answer is below.

The code of our test HTML page already contains JS function onClick():

pic_9.png

Now let us try to call this function inside the 1C:Enterprise platform. Add one more command to the form:

pic_10.png

And the source code to process this command:

&AtClient

Procedure Click(Command)

           

            workWindow = returnWorkWindow();

           

            workWindow.onClick();

           

EndProcedure

&AtClient

Function returnWorkWindow()

            workWindow = Items.HTML.Document.parentWindow; // for IE

           

            If workWindow = Undefined Then

                    workWindow = Items.HTML.Document.defaultView;

            EndIf;

           

            Return workWindow;

EndFunction

At step one, we get the work window of our so-called browser. Note that, depending on the default system browser, we access either attribute parentWindow (with IE used as the default browser) or defaultView.

With the work window open, the procedures and functions declared inside the HTML page become available. Thus, we can safely call function onClick(), existing in the JS script, directly from the 1C:Enterprise platform.

Let us see it in action. Here we go:

pic_11.png

As you can see (and there is no magic here), we can access the JavaScript environment via the 1C code and run a required function there.

Ok. Let us take a step further. As we can safely run JS scripts inside 1C, why not try something unusual, for example, add a simple game written in JS? And then, we will try to control this game externally from the 1C runtime environment.

So, we add a new template to our data processor:

pic_12.png

As you can see from the template's name, we want to run the Tic-Tac-Toe game inside the platform. We place the game's source code in the template:

pic_13.png

Then we add to the form command Load game with the following source code:

&AtClient

Procedure cmdLoadGame1(Command)

            HTML = GetTemplate("TemplateTicTacToe");

           

EndProcedure

As you can see, everything is simple. We load the source code for JS from the template into the HTML element. And that is all! Time to see it in action.

pic_14.png

Of course, the source code that controls your opponent in this game is not perfect, but it is no doubt this game will give you a couple of minutes of pleasure.

But let us move on! Why not try controlling this game right via the 1C code?

At the end of each game, regardless of the result, the player gets the Play again link on the home screen:

pic_15_1.png

A click on this link restarts the game. Let us place the functionality of this link to the platform and restart the game right from the 1C:Enterprise platform itself.

In the JS code, a click on the Play Again link launches the following function:

pic_16.png

It is the function we need to call from the 1C:Enterprise platform. I have already described how to do it earlier in this article.

Add one more command to the form:

pic_17.png

And insert the code:

&AtClient

Procedure cmdPlayAgain(Command)

           

            workWindow = returnWorkWindow();

           

            workWindow.playAgain();

           

EndProcedure

Run the platform and try it. It works!

pic_18.png

Let us not stop there and add another game to our data processor, for example, the Snake.

We act precisely the same way. We add a new template that will store the game's JS source code:

pic_19.png

Then add a new command to the form:

pic_20_new.png

And the program code to process this command:

&AtClient

Procedure cmdLoadGame2(Command)

           

            HTML = GetTemplate("TemplateSnake");

           

EndProcedure

Run the code and see in action:

pic_21_new.png

Voila. It works like a charm! Congratulations! We are through with the first part.

Now let us place the snake controls out of the JS code into the 1C:Enterprise platform. To do this, we add to the JS script four functions to control the snake's movement and call these functions through the 1C code.

We modify the JS script as follows:

pic_22.png

And then, on the form, we place four commands that should call these functions and control the snake:

pic_23_new.png

And, of course, in the platform, we add the code to call the necessary functions in the JS script:

&AtClient

Procedure cmdToLeft(Command)

           

workWindow = returnWorkWindow();

           

            workWindow.toLeft();

EndProcedure

&AtClient

Procedure cmdToRight(Command)

workWindow = returnWorkWindow();

           

            workWindow.toRight();

           

EndProcedure

&AtClient

Procedure cmdToUp(Command)

workWindow = returnWorkWindow();

           

            workWindow.toUp();

           

EndProcedure

&AtClient

Procedure cmdToDown(Command)

workWindow = returnWorkWindow();

           

            workWindow.toDown();

           

EndProcedure

Now we launch the platform and check if everything is ok. And it is. The snake can be perfectly controlled from the 1C:

pic_24_new.png

Up to this point, we have only called JS functions from 1C code. Now, let us try to transfer data from the platform to JavaScript.

Here it is necessary to give a small comment. In general, if the 1C:Enterprise platform is running on Windows, then not only primitive data types, such as String or Boolean, but also complex types utilized in the platform, such as Structure, Array, Map, and Form, can be passed to a JS script.

For example, we can pass an array previously generated in 1C code to a JS function. When in JS, we can access the array's property Count(), though in JS, this property is called Length. Also, we can pass the entire form to JS and access all the form's properties and methods from there.

It might seem very convenient. Still, as soon as we start exchanging data utilizing this method, we deliberately give up the cross-platform nature of our application. Just remember the data transfer method for complex data types only works on Windows. So, if the 1C:Enterprise platform is running on Linux or in a browser, no data transfer will occur.

Therefore, I do not recommend passing data with this method, and for this reason, I am not giving any relevant examples.

Well, if we cannot pass an array to a JS script, then what should we do? Remember that we can transfer data of type String, which means we can transfer any object from the platform inside JS after converting it to JSON.

Here is a small example. Create an array in the 1C:Enterprise. We want to use it to store information about the buttons that need to be created on the HTML page (button text, color, etc.). Now we pass this array from 1C to the JS script, and the JS script adds controls to the form using this data.

Let's go!

As usual, we start with creating an HTML page template:

pic_25.png

And put a function inside the template:

pic_26.png

Judging by the code, the function receives an input parameter representing an array with information about the buttons recorded in JSON format. Then, the function creates a new DIV element and adds as many buttons to this element as included in the passed array.

Next, we add command LoadTemplateButtons to the form:

pic_27_new.png

And the code to handle this command:

&AtClient

Procedure LoadTemplateButtons(Command)

           

            HTML = GetTemplate("TemplateButtons");

           

EndProcedure

The only thing this command does is load the page's HTML code into the HTML control.

The command we create is CreateButtons. Its role is to create new HTML elements:

pic_28_new.png

Here is the command's code:

&AtClient

Procedure cmdCreateButtons(Command)

           

            workWindow = returnWorkWindow();

           

            arrayButtons = New Array;

           

            For counter = 0 To 4 Do

                             

                   structureButton = New Structure;

                             

                   structureButton.Insert("id",             "button" + counter);

                   structureButton.Insert("innerText", "Button_" + counter);

                   structureButton.Insert("fontSize", 10 + counter*2);

                   structureButton.Insert("color",      RandomColor());

                             

                   arrayButtons.Add(structureButton);

                             

            EndDo;

           

            workWindow.createButtons(toJSON(arrayButtons));

           

EndProcedure

As you can see, the platform creates an array of five elements that get information about button names, font size, and color.

The color is randomly selected from five colors. To make it simple, I am not providing the source text of function RandomColor() and function toJSON(). Still, at the end of the article, you can find the complete source code if you wish to see how it is all implemented.

Finally, we can check how it works. Open the data processor in the 1C:Enterprise platform, click Load template buttons, and then Create buttons.

The result:

pic_29.png

You can click multiple times:

pic_30.png

Let us make our code a little more complicated. When creating an array in the 1C:Enterprise, we want to receive a random color from a JS script. That is, we will abandon the platform's function RandomColor() and use a similar function inside the JS code instead.

So we modify our JS code:

pic_31.png

As you can see, the function randomly returns one of the five colors.

Then we change the source code in the 1C:Enterprise platform, replacing the call to function RandomColor() from 1C with a similar call, but only from a JS script:

pic_32.png

Well, let's check the result:

pic_33.png

It seems we are through with the task. So, what have we got? We learned how to run code written in JavaScript from a 1C application. We are able to call functions declared in JS directly from the 1C:Enterprise platform. And finally, we now know how to transfer data between the 1C execution context and JS.

You might wonder what the benefit of using JS scripts is. Is it really just about games and other entertainment? Definitely not! Thus, using HTML and CSS in combination with JS, developers can create unique user interfaces that look different from the standard one of the 1C:Enterprise, but still retain the platform's full functionality.

For example, in this article see how pretty mobile applications created with HTML can be.

Example

Also, developers can implement the functionality for interactive mapping of goods delivery routes based on both Google maps and JS scripts running right inside the respective 1C application.

In a word, the scope is limited only by your imagination!

It makes it all for today. 

As usual, I am glad to share the link to the example we have used in this article. 

And traditionally say ... stay with us! There is still a lot of exciting stuff ahead!

Be the first to know tips & tricks on business application development!

A confirmation e-mail has been sent to the e-mail address you provided .

Click the link in the e-mail to confirm and activate the subscription.