Introduction to RD3 JavaScript components
copy linkIntroduction
Since its beginnings, Instant Developer has allowed programmers to customize the applications they develop with it. The IDE can be customized, and so can the templates the IDE uses to generate web applications. Customizing the server portion with the addition of C#/Java/JavaScript classes has always been easier than customizing the user interface: adding a new graphic component that's not already part of the template is complicated.
In version 20.0 of Instant Developer, we've tried to make it easier to add new third-party client components. In particular, we tried to simplify integration with the pre-existing framework, making it possible to insert graphic objects and integrate them with the Instant Developer framework.
Below we'll look at how to integrate a JavaScript component.
Defining the interface in the IDE
First of all we need to define in the project a library that describes how the client object is made. This new library is the "client library" type, and is added using the corresponding context menu command in the project.


If the parameter is an IDMap type, the client counterpart will be an Object type. If instead the parameter is an IDArray type, it will be mapped with a client array.
Note 1: There is no need to indicate the expression in C# or Java: Instant Developer calculates it automatically each time the name of the function changes.
Note 2: Other types of objects cannot be specified because they must be serializable in JSON.
Note 3: Functions cannot be defined, because since the communication with JavaScript takes place asynchronously, there is no way to obtain a value synchronously.
Using in frames
Once the client library has been defined, which describes how the corresponding JavaScript object is made, it's possible to tell Instant Developer where to use it.
To do so, simply drag the library into the form frames or into static fields (like any other frame: panels, trees, books, graphics, etc.).


Using in in-list fields
Beginning with version 21.0, custom components can also be used in in-list panel fields.
To do so simply drag the library to the panel field (the one with the yellow icon) in the tree, or directly from the form preview.

In the designer nothing will be displayed except for the name of the client library that is connected to the panel field.
To interact with in-list objects, you must set the properties and invoke the methods in the OnDynamicProperties event, while for fields not in list or detail you can do so at any other point in the code.

Client-side wrapper class
To make it easier to insert any graphic object, we need an interface class written in JavaScript. This class is what is inserted between the Instant Developer framework (RD3) and the third-party client object.
At the end of the article you can download a wrapper class template with everything you need to get started.
This class must have the same characteristics as the client library that we defined in the project. It must have the same properties and possess the same methods that we have defined in the library inside the project.
This file will be inserted in the application's custom directory in which we use the client library. Any other files used by the third-party client objects must also be inserted in the custom directory, such as JavaScript files, fonts, CSS, etc.
The path to the JavaScript interface file must be indicated in the client library properties form. Later on we'll see how the file must be written.

Warning: If the Desktop.htm and/or Desktop_sm.htm files have already been customized, they will need to be realigned with the template by entering the new macros that have been inserted and which Instant Developer will use to insert the JavaScript wrapper file.
Now let's see how the wrapper class written in JavaScript must be defined. First of all, the name of the class must match the name of the file. If the class is called MyClientLibrary, the file must be called MyClientLibrary.js. In fact, Instant Developer uses the file name to create the instance of the client-side JavaScript class where necessary.
The wrapper class must extend the class of the CustomElement framework as shown in the following example:
function MyClientLibrary(owner)
{
// Call base constructor
CustomElement.call(this, owner);
//
// Initialization of properties
}
//
// Define extension of class
MyClientLibrary.prototype = new CustomElement();
The CustomElement base class defines certain methods that the RD3 framework calls automatically when the element is created (because the form is opened) and destroyed (because the form is closed). These methods are to be implemented in their own class. The actual client object must be created inside these methods. The code to use depends on the object you want to create. For this, refer to the documentation for the graphic component and write the corresponding code.
In the Realize method, the client object DOM objects must be created. The parent parameter can be used to attach DOM objects to those already existing in the application.
In the Unrealize method, the objects entered in the Realize method must be destroyed (removed from the DOM).
MyClientLibrary.prototype.Realize = function (parent)
{
// Call base method
CustomElement.prototype.Realize.call(this, parent);
//
// Create the element
}
MyClientLibrary.prototype.Unrealize = function ()
{
// Call base method
CustomElement.prototype.Unrealize.call(this);
//
// Destroy the element
}
Properties set server side are automatically sent to the client. For example, if the library has its own property called center, and server side we write
[subform].center = true
the system will send out that value to the client as soon as the response to send to the browser is prepared. Therefore, client side, the "this.center" property will be set to true. If it's necessary to be informed when the server changes the property (because, for example, you want to do something to the component when the property changes) a getter/setter must be defined for the property as follows:
Object.defineProperty(MyClientLibrary.prototype, "propertyName", {
get: function () {
return ...;
},
set: function (value) {
...
}
});
Loading dependencies
To load the files for the graphic object (e.g.: JavaScript files, CSS files) there are two ways to proceed:
- insert the files in the Desktop.htm and Desktop_sm.htm files
- load them dynamically when the form containing the graphic object is opened the first time
CustomElement.LoadRequirements = function (urls, type, callback)The first parameter indicates which resources to load. This can be a URL (relative or absolute) or an array of URLs (relative or absolute). If an array of URLs is provided, loading follows the order of the URLs in the array and in sequence. The array should be used if you need to load the files in a specific order.
The second parameter indicates the type of resource to be loaded: "JS" or "CSS".
The third parameter is a function that the system calls when loading is complete (callback).
Firing events and changes to properties
To fire an event to the server, write the following code:
this.SendEvent("eventName", [par1, par2, ...]);
The first parameter is the name of the event without spaces as defined in the project client library. The second parameter (optional if the event has no parameters) is an array inside which to insert the values of various parameters.
If you want to send the value of a property to a server, the SendProperty method must be called:
this.SendProperty("propertyName", propertyValue);
In this case as well the name of the property must be that indicated in the client library of the project, removing any spaces. The second parameter is the value of the property. If not specified, the system automatically sends the value of this.propertyName.
Methods for frames
When the component is used in a frame, the framework invokes the AdaptLayout() method, overriding which you can adapt the DOM object to the object that contains it.
Methods for in-list fields
When the component is used in a panel field, the framework invokes a series of methods.
To have the component draw itself/behave the way you want, the necessary methods must be overridden (they don't necessarily all need to be overridden).
These are the methods that the framework invokes:
- GetDOMObj(): called to have the main DOM object (must mandatorily be invoked).
- SetValue(value): called when the value of the field changes.
- GetValue(): called to learn the value of the field.
- SetEnabled(enabled): called when the field enabled status changes.
- SetVisible(visible): called when the field visibility status changes.
- SetActive(active): called when the field activation status changes.
- SetLeft(x): called to set the left position.
- SetTop(y): called to set the top position.
- SetWidth(w): called to set the width.
- SetHeight(y): call to set the height.
- SetVisualStyle(vs): called when the visual style associated with the field changes.
- SetBackGroundImage(img): called when the background image of the field changes.
- HideContent(hide, disable): called when the content of the field must be cleared (for example if the panel moves to QBE).
- UpdateCell(): called at the end of every request in which it's possible to read all the properties of the component and consequently update the DOM.
- CanHaveFocus(): called to find out if the field can receive focus.
- Focus(): called when the field must have focus.
Changed on: 17/11/2023 / From version: 20.0.7800