3.5.17.2. Generic JavaScriptComponent

JavaScriptComponent is a simple UI component that can work with any JavaScript wrapper without Vaadin component implementation. Thus, you can easily integrate any pure JavaScript component in your CUBA-based application.

The component can be defined declaratively in an XML descriptor of the screen, so that you can configure dynamic properties and JavaScript dependencies in XML.

XML-name of the component: jsComponent.

Defining dependencies

You can define a list of dependencies (JavaScript, CSS) for the component. A dependency can be obtained from the following sources:

  • WebJar resource - starts with webjar://

  • File placed within VAADIN directory - starts with vaadin://

  • Web resource - starts with http:// or https://

If the type of dependency cannot be inferred from the extension, specify the type explicitly in the type XML attribute or by passing DependencyType enum value to the addDependency() method.

Example of defining dependencies in XML:

<jsComponent ...>
    <dependencies>
        <dependency path="webjar://leaflet.js"/>
        <dependency path="http://code.jquery.com/jquery-3.4.1.min.js"/>
        <dependency path="http://api.map.baidu.com/getscript?v=2.0"
                    type="JAVASCRIPT"/>
    </dependencies>
</jsComponent>

Example of adding dependencies programmatically:

jsComponent.addDependencies(
        "webjar://leaflet.js",
        "http://code.jquery.com/jquery-3.4.1.min.js"
);
jsComponent.addDependency(
        "http://api.map.baidu.com/getscript?v=2.0", DependencyType.JAVASCRIPT
);
Defining initialization function

The component requires an initialization function. This function’s name that will be used to find an entry point for the JavaScript component connector (see below).

The initialization function name must be unique within a window.

The function name can be passed to the component using the setInitFunctionName() method:

jsComponent.setInitFunctionName("com_company_demo_web_screens_Sandbox");
Defining JavaScript connector

To use JavaScriptComponent wrapper for a library, you should define a JavaScript connector - a function that initializes the JavaScript component and handles communication between the server-side and the JavaScript code.

The following methods are available from the connector function:

  • this.getElement() returns the HTML DOM element of the component.

  • this.getState() returns a shared state object with the current state as synchronized from the server-side.

Component features

The JavaScriptComponent component has the following features that let you:

  • Set a state object that can be used in the client-side JavaScript connector and is accessible from the data field of the component’s state, for example:

    MyState state = new MyState();
    state.minValue = 0;
    state.maxValue = 100;
    jsComponent.setState(state);
  • Register a function that can be called from the JavaScript using the provided name, for example:

    jsComponent.addFunction("valueChanged", callbackEvent -> {
        JsonArray arguments = callbackEvent.getArguments();
    
        notifications.create()
                .withCaption(StringUtils.join(arguments, ", "))
                .show();
    });
    this.valueChanged(values);
  • Invoke a named function that the connector JavaScript has added to the JavaScript connector wrapper object.

    jsComponent.callFunction("showNotification ");
    this.showNotification = function () {
            alert("TEST");
    };
JavaScriptComponent usage example

This section describes how to integrate a third-party JavaScript library to a CUBA-based application taking Quill Rich Text Editor from https://quilljs.com/ as an example. To use Quill in your project, you should follow the steps below.

  1. Add the following dependency to the web module:

    compile('org.webjars.npm:quill:1.3.6')
  2. Create a quill-connector.js file in the web/VAADIN/quill directory on the web module.

  3. In this file, add the connector implementation:

    com_company_demo_web_screens_Sandbox = function () {
        var connector = this;
        var element = connector.getElement();
        element.innerHTML = "<div id=\"editor\">" +
            "<p>Hello World!</p>" +
            "<p>Some initial <strong>bold</strong> text</p>" +
            "<p><br></p>" +
            "</div>";
    
        connector.onStateChange = function () {
            var state = connector.getState();
            var data = state.data;
    
            var quill = new Quill('#editor', data.options);
    
            // Subscribe on textChange event
            quill.on('text-change', function (delta, oldDelta, source) {
                if (source === 'user') {
                    connector.valueChanged(quill.getText(), quill.getContents());
                }
            });
        }
    };
  4. Create a screen with the following jsComponent definition:

    <jsComponent id="quill"
                 initFunctionName="com_company_demo_web_screens_Sandbox"
                 height="200px"
                 width="400">
        <dependencies>
            <dependency path="webjar://quill:dist/quill.js"/>
            <dependency path="webjar://quill:dist/quill.snow.css"/>
            <dependency path="vaadin://quill/quill-connector.js"/>
        </dependencies>
    </jsComponent>
  5. Add the following screen controller implementation:

    @UiController("demo_Sandbox")
    @UiDescriptor("sandbox.xml")
    public class Sandbox extends Screen {
        @Inject
        private JavaScriptComponent quill;
    
        @Inject
        private Notifications notifications;
    
        @Subscribe
        protected void onInit(InitEvent event) {
            QuillState state = new QuillState();
            state.options = ParamsMap.of("theme", "snow",
                    "placeholder", "Compose an epic...");
    
            quill.setState(state);
    
            quill.addFunction("valueChanged", javaScriptCallbackEvent -> {
                String value = javaScriptCallbackEvent.getArguments().getString(0);
                notifications.create()
                        .withCaption(value)
                        .withPosition(Notifications.Position.BOTTOM_RIGHT)
                        .show();
            });
        }
    
        class QuillState {
            public Map<String, Object> options;
        }
    }

As a result, the Quill Rich Text Editor is available on the screen:

jsComponent example

Another example of custom JavaScript component integration see at Using a JavaScript library.