3.5.17.4.3. Подключение JavaScript библиотеки
В платформе CUBA реализован компонент Slider, позволяющий получить числовое значение в заданном диапазоне. Для ваших задач может понадобиться подобный компонент с двумя ползунками, определяющими диапазон значений. Поэтому в данном примере мы подключим компонент Slider из библиотеки jQuery UI.
Создайте новый проект в CUBA Studio и назовите его jscomponent
.
Чтобы создать Slider компонент, необходимо создать следующие файлы:
-
SliderServerComponent
- интегрированный с JavaScript компонент Vaadin. -
SliderState
- класс состояния компонента Vaadin. -
slider-connector.js
- JavaScript коннектор для компонента Vaadin
Процесс интеграции компонента в универсальный интерфейс аналогичен описанному в разделе Подключение аддона Vaadin с интеграцией в Generic UI, поэтому рассматривать его здесь мы не будем.
Создадим требуемые файлы в подкаталоге toolkit/ui/slider
модуля web и внесем в них необходимые изменения.
-
Класс состояния
SliderState
определяет, какие данные будут пересылаться между сервером и клиентом. В нашем случае мы будем пересылать информацию о минимальном и максимальном возможном значении и выбранных значениях слайдера.package com.company.jscomponent.web.toolkit.ui.slider; import com.vaadin.shared.ui.JavaScriptComponentState; public class SliderState extends JavaScriptComponentState { public double[] values; public double minValue; public double maxValue; }
-
Серверный компонент Vaadin
SliderServerComponent
.package com.company.jscomponent.web.toolkit.ui.slider; import com.haulmont.cuba.web.widgets.WebJarResource; import com.vaadin.annotations.JavaScript; import com.vaadin.ui.AbstractJavaScriptComponent; import elemental.json.JsonArray; @WebJarResource({"jquery:jquery.min.js", "jquery-ui:jquery-ui.min.js", "jquery-ui:jquery-ui.css"}) @JavaScript({"slider-connector.js"}) public class SliderServerComponent extends AbstractJavaScriptComponent { public interface ValueChangeListener { void valueChanged(double[] newValue); } private ValueChangeListener listener; public SliderServerComponent() { addFunction("valueChanged", arguments -> { JsonArray array = arguments.getArray(0); double[] values = new double[2]; values[0] = array.getNumber(0); values[1] = array.getNumber(1); getState(false).values = values; listener.valueChanged(values); }); } public void setValue(double[] value) { getState().values = value; } public double[] getValue() { return getState().values; } public double getMinValue() { return getState().minValue; } public void setMinValue(double minValue) { getState().minValue = minValue; } public double getMaxValue() { return getState().maxValue; } public void setMaxValue(double maxValue) { getState().maxValue = maxValue; } @Override protected SliderState getState() { return (SliderState) super.getState(); } @Override public SliderState getState(boolean markAsDirty) { return (SliderState) super.getState(markAsDirty); } public ValueChangeListener getListener() { return listener; } public void setListener(ValueChangeListener listener) { this.listener = listener; } }
Серверный компонент Vaadin определяет набор геттеров и сеттеров для работы с состоянием слайдера, а также интерфейс слушателя изменения значений. Класс компонента должен быть унаследован от
AbstractJavaScriptComponent
.Метод
addFunction()
в конструкторе класса объявляет обработчик RPC-вызова функцииvalueChanged()
с клиента.Аннотации
@JavaScript
и@WebJarResource
указывают на файлы, которые должны быть загружены на веб-страницу. В нашем примере это JavaScript файлы библиотеки jQuery UI, а также файл со стилями для jQuery UI, расположенные в WebJar ресурсе, и файл коннектора, расположенный в одном Java-пакете с серверным компонентом. -
JavaScript коннектор
slider-connector.js
.com_company_jscomponent_web_toolkit_ui_slider_SliderServerComponent = function() { var connector = this; var element = connector.getElement(); $(element).html("<div/>"); $(element).css("padding", "5px 0px"); var slider = $("div", element).slider({ range: true, slide: function(event, ui) { connector.valueChanged(ui.values); } }); connector.onStateChange = function() { var state = connector.getState(); slider.slider("values", state.values); slider.slider("option", "min", state.minValue); slider.slider("option", "max", state.maxValue); $(element).width(state.width); } }
Коннектор представляет собой функцию, которая при загрузке веб-страницы проинициализирует JavaScript компонент. Имя функции должно соответствовать полному имени класса серверного компонента, где точки в имени пакета заменены на символ подчеркивания.
Vaadin добавляет ряд полезных методов в функцию коннектора. Например,
this.getElement()
возвращает HTML DOM элемент компонента,this.getState()
возвращает объект-состояние.В нашем примере коннектор делает следующее:
-
Инициализирует компонент
slider
из библиотеки jQuery UI. При изменении положения одного из ползунков будет вызвана функцияslide()
. Мы видим, что она в свою очередь вызывает методvalueChanged()
коннектора.valueChanged()
- это метод, который мы объявили на стороне сервера в классеSliderServerComponent
. -
Объявляет функцию
onStateChange()
. Она будет вызываться при изменении объекта-состояния на стороне сервера.
-
Для демонстрации работы компонента создадим сущность Product
с тремя атрибутами:
-
name
типа String -
minDiscount
типа Double -
maxDiscount
типа Double
Затем сгенерируем стандартные экраны для данной сущности. Обратите внимание, что мы используем не универсальный компонент платформы, а "нативный" компонент Vaadin. Следовательно, экраны должны располагаться в модуле Web, а не в GUI - укажите это в окне генерации стандартных экранов.
В редакторе сущности мы хотим устанавливать минимальное и максимальное значение скидки с помощью компонента slider
, который мы только что создали.
Перейдите к файлу product-edit.xml
. Поля minDiscount
и maxDiscount
сделайте нередактируемыми, добавив к соответствующим элементам атрибут editable="false"
. Затем добавьте компонент hbox
, который будет использоваться в качестве контейнера для Vaadin компонента.
В результате XML-дескриптор экрана редактирования должен выглядеть следующим образом:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="msg://editorCaption"
focusComponent="form"
messagesPack="com.company.jscomponent.web.product">
<data>
<instance id="productDc"
class="com.company.jscomponent.entity.Product"
view="_local">
<loader/>
</instance>
</data>
<dialogMode height="600"
width="800"/>
<layout expand="editActions" spacing="true">
<form id="form" dataContainer="productDc">
<column width="250px">
<textField id="nameField" property="name"/>
<textField id="minDiscountField" property="minDiscount" editable="false"/>
<textField id="maxDiscountField" property="maxDiscount" editable="false"/>
<hbox id="sliderBox" width="100%"/>
</column>
</form>
<hbox id="editActions" spacing="true">
<button action="windowCommitAndClose"/>
<button action="windowClose"/>
</hbox>
</layout>
</window>
Перейдите к файлу ProductEdit.java
. Замените его содержимое следующим кодом:
package com.company.jscomponent.web.product;
import com.company.jscomponent.entity.Product;
import com.company.jscomponent.web.toolkit.ui.slider.SliderServerComponent;
import com.haulmont.cuba.gui.components.HBoxLayout;
import com.haulmont.cuba.gui.screen.*;
import com.vaadin.ui.Layout;
import javax.inject.Inject;
@UiController("jscomponent_Product.edit")
@UiDescriptor("product-edit.xml")
@EditedEntityContainer("productDc")
@LoadDataBeforeShow
public class ProductEdit extends StandardEditor<Product> {
@Inject
private HBoxLayout sliderBox;
@Subscribe
protected void onInitEntity(InitEntityEvent<Product> event) {
event.getEntity().setMinDiscount(15.0);
event.getEntity().setMaxDiscount(70.0);
}
@Subscribe
protected void onBeforeShow(BeforeShowEvent event) {
SliderServerComponent slider = new SliderServerComponent();
slider.setValue(new double[]{
getEditedEntity().getMinDiscount(),
getEditedEntity().getMaxDiscount()
});
slider.setMinValue(0);
slider.setMaxValue(100);
slider.setWidth("250px");
slider.setListener(newValue -> {
getEditedEntity().setMinDiscount(newValue[0]);
getEditedEntity().setMaxDiscount(newValue[1]);
});
sliderBox.unwrap(Layout.class).addComponent(slider);
}
}
В методе onInitEntity()
мы проставляем начальные значения скидок для нового продукта.
В методе onBeforeShow()
инициализируем компонент слайдера. Для компонента слайдера мы проставляем текущие значения, максимальное и минимальное значения, а также объявляем слушатель изменений значений. При движении ползунка мы будем проставлять новые значения скидок в соответствующие поля редактируемой сущности.
Запустите проект и откройте экран редактирования продукта. Изменение положения ползунка на слайдере должно изменять значение в соответствующем текстовом поле.