Универсальный JavaScriptComponent

JavaScriptComponent – это простой компонент пользовательского интерфейса, который представляет собой универсальную обертку для использования любой готовой библиотеки JavaScript в приложении на базе Jmix напрямую, без необходимости подключать компонент Vaadin.

Компонент можно использовать в XML-дескрипторе экрана, чтобы декларативно настраивать динамические свойства и зависимости JavaScript.

XML-имя компонента: jsComponent.

Определение зависимостей

Вы можете задать для компонента несколько зависимостей (JavaScript, CSS). Каждая зависимость должна соответствовать одному из следующих источников:

  • Ресурс WebJar - начинается с webjar://.

  • Файл, расположенный в локальном каталоге VAADIN, начинается с vaadin://.

  • Веб-ресурс — начинается с http:// или https://.

Список зависимостей определяется в элементе dependencies. Каждая зависимость описывается во вложенном элементе dependency.

Укажите путь зависимости в атрибуте path.

Пример определения зависимостей в 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>

Если тип зависимости нельзя вывести из расширения, укажите тип явно в XML-атрибуте type.

Зависимость можно добавить программно, используя метод addDependency(). Чтобы указать тип зависимости, передайте методу DependencyType значение перечисления addDependency().

Пример добавления зависимостей программно:

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);

Определение функции инициализации

Для компонента необходимо задать функцию инициализации. Имя этой функции будет использовано JavaScript-коннектором для поиска точки входа.

В пределах окна имя функции инициализации должно быть уникальным.

Укажите имя функции в атрибуте initFunctionName компонента jsComponent.

Имя функции можно передать в компонент с помощью метода setInitFunctionName():

timePicker.setInitFunctionName("ui_ex1_components_javascript_TimePicker");

Определение JavaScript-коннектора

Чтобы использовать компонент JavaScriptComponent для подключения библиотеки JavaScript, вам необходимо создать JavaScript-коннектор – функцию, которая будет инициализировать компонент JavaScript и управлять коммуникацией между сервером и кодом JavaScript.

Из функции коннектора доступны следующие методы:

  • this.getElement() возвращает HTML DOM элемент компонента.

  • this.getState() возвращает распределенный объект состояния с текущим состоянием компонента как синхронизируемый объект с серверной стороны.

Возможности компонентов

Ниже перечислены возможности компонента JavaScriptComponent, которые позволяют следующее:

  • Задать объект состояния, который можно использовать в коннекторе на стороне клиента и который будет доступен в поле data состояния компонента, к примеру:

    TimePickerState state = new TimePickerState();
    
    state.now = "12:35:57";
    state.showSeconds = true;
    state.twentyFour = true;
    
    timePicker.setState(state);
  • Зарегистрировать функцию, которая может быть вызвана из кода JavaScript по указанному имени, например:

    timePicker.addFunction("onBeforeShow", callbackEvent ->
            notifications.create()
                    .withCaption("Before Show Event")
                    .withPosition(Notifications.Position.MIDDLE_RIGHT)
                    .show());
  • Вызвать именованную функцию, которую JavaScript-коннектор добавил к объекту-обертке коннектора.

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

Использование JavaScriptComponent

В этом разделе описан пример интеграции сторонней JavaScript-библиотеки в приложение на основе Jmix на примере Quill Rich Text Editor. Чтобы использовать Quill в своем проекте, необходимо выполнить шаги, описанные ниже.

  1. Добавьте следующую зависимость в файл build.gradle:

    implementation 'org.webjars.npm:quill:1.3.6'
  2. Создайте файл quill-connector.js в каталоге src/main/resources/VAADIN/quill.

  3. Добавьте в этот файл код реализации коннектора:

    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 Обработка изменений со стороны сервера.
    2 Подписка на событие textChange.
  4. Создайте экран с описанием компонента jsComponent:

    <?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. Контроллер этого экрана включает в себя следующую реализацию:

    @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;
        }
    }

В результате компонент Quill Rich Text Editor доступен на экране:

java script component

Все XML-атрибуты

Просматривать и редактировать атрибуты, применимые к компоненту, можно с помощью панели инспектора Jmix UI в конструкторе экранов Studio.

XML-элементы JavaScriptComponent

XML-атрибуты зависимостей