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 Jmix-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://.

The list of dependencies is defined in the dependencies element. Each dependency is described in a nested dependency element.

Specify a dependency path in the path attribute.

Example of defining dependencies in XML:

<jsComponent id="timePicker"
             initFunctionName="ui_ex1_components_javascript_TimePicker">
    <dependencies>
        <dependency path="webjar://jquery:jquery.min.js"
                    type="JAVASCRIPT"/>
        <dependency path="vaadin://timepicker/wickedpicker.min.js"/>
        <dependency path="vaadin://timepicker/wickedpicker.min.css"/>
        <dependency path="vaadin://timepicker/time-picker-connector.js"/>
    </dependencies>
</jsComponent>

If the type of dependency cannot be inferred from the extension, specify the type explicitly in the type XML attribute.

You can add a dependency programmatically using the addDependency() method. To specify the type of dependency, pass the DependencyType enum value to the addDependency() method.

Example of adding dependencies programmatically:

timePicker.addDependencies(
        "webjar://jquery:jquery.min.js",
        "vaadin://timepicker/wickedpicker.min.js",
        "vaadin://timepicker/time-picker-connector.js");
timePicker.addDependency("vaadin://timepicker/wickedpicker.min.css",
        JavaScriptComponent.DependencyType.STYLESHEET);

Defining Initialization Function

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

The initialization function name must be unique within a window.

Specify the function name in the initFunctionName attribute of jsComponent.

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

timePicker.setInitFunctionName("ui_ex1_components_javascript_TimePicker");

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

JavaScriptComponent 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:

    TimePickerState state = new TimePickerState();
    
    state.now = "12:35:57";
    state.showSeconds = true;
    state.twentyFour = true;
    
    timePicker.setState(state);
  • Register a function that can be called from the JavaScript using the provided name, for example:

    timePicker.addFunction("onBeforeShow", callbackEvent ->
            notifications.create()
                    .withCaption("Before Show Event")
                    .withPosition(Notifications.Position.MIDDLE_RIGHT)
                    .show());
  • Invoke a named function that the JavaScript connector has added to the connector wrapper object.

    timePicker.callFunction("showValue");
    connector.showValue = function () {
        alert(timepicker.wickedpicker('time'));
    };

Using JavaScriptComponent

This section describes integrating a third-party JavaScript library to a Jmix-based application taking Quill Rich Text Editor as an example. To use Quill in your project, you should follow the steps below.

  1. Add the following dependency to the build.gradle file:

    implementation 'org.webjars.npm:quill:1.3.6'
  2. Create the quill-connector.js file in the src/main/resources/VAADIN/quill directory.

  3. In this file, add the connector implementation:

    ui_ex1_components_javascript_RichTextEditor = 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 () { (1)
            var state = connector.getState();
            var data = state.data;
    
            var quill = new Quill('#editor', data.options);
    
            quill.on('text-change', function (delta, oldDelta, source) { (2)
                if (source === 'user') {
                    connector.valueChanged(quill.getText(), quill.getContents());
                }
            });
        }
    };
    1 Handle changes from the server-side.
    2 Subscribe on the textChange event.
  4. Create a screen with the following jsComponent definition:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <window xmlns="http://jmix.io/schema/ui/window"
            caption="msg://richTextEditorScreen.caption">
        <layout>
            <jsComponent id="quill"
                         initFunctionName="ui_ex1_components_javascript_RichTextEditor"
                         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>
        </layout>
    </window>
  5. Add the following screen controller implementation:

    @UiController("sample_RichTextEditorScreen")
    @UiDescriptor("rich-text-editor-screen.xml")
    public class RichTextEditorScreen extends Screen {
        @Autowired
        private JavaScriptComponent quill;
    
        @Autowired
        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:

java script component

All XML Attributes

You can view and edit attributes applicable to the component using the Component Inspector panel of the Studio’s Screen Designer.

JavaScriptComponent XML Elements

Dependency XML Attributes