4.5.6.3. Using a JavaScript library
In this example, we will use the Slider component from the jQuery UI library. The slider will have two drag handlers that define a values range.
Create a new project in CUBA Studio and name it jscomponent
.
Click the New UI component button on the Project properties navigator section. The UI component generation will open. Select the JavaScript component
value in the Component type
section.
Enter SliderServerComponent
in the Vaadin component class name field.
Deselect the Integrate into Generic UI flag. The process of integration into the Generic UI is the same as described at Integrating a Vaadin Component into the Generic UI, so we won’t repeat it here.
After clicking the OK button Studio will generate the following files:
-
SliderServerComponent
- a Vaadin component integrated with JavaScript. -
SliderState
- a state class of the Vaadin component. -
slider-connector.js
- a JavaScript connector for the Vaadin component.
Let’s examine the generated files and make necessary changes in the source code.
-
SlideState
state class defines what data is transferred between the server and the client. In our case it is a minimal possible value, maximum possible value and selected values.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 server-side component
SliderServerComponent
.package com.company.jscomponent.web.toolkit.ui.slider; import com.vaadin.annotations.StyleSheet; import com.vaadin.ui.AbstractJavaScriptComponent; import com.vaadin.annotations.JavaScript; import elemental.json.JsonArray; @JavaScript({"slider-connector.js", "jquery-ui.js"}) @StyleSheet({"jquery-ui.css"}) 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; } }
The server component defines getters and setters to work with the slider state and an interface of value change listeners. The class extends
AbstractJavaScriptComponent
.The
addFunction()
method invocation in the class constructor defines a handler for an RPC-call of thevalueChanged()
function from the client.The
@JavaScript
and@StyleSheet
annotations point to files that must be loaded on the web page. In our example, these are JavaScript files of the jquery-ui library, the connector and the stylesheet for jquery-ui. You should place these files to the Java package of the Vaadin server component.
Download an archive with jQuery UI from http://jqueryui.com/download and put files jquery-ui.js
and jquery-ui.css
from the archive to the Java package of the SliderServerComponent
class. At the jQuery UI download page, you can select which components should be put into the archive. For this demo, it is enough to select only the Slider
item of the Widgets
group.
-
JavaScript connector
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 10px"); 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); } }
Connector is a function that initializes a JavaScript component when the web page is loaded. The function name must correspond to the server component class name where dots in package name are replaced with underscore characters.
Vaadin adds several useful methods to the connector function.
this.getElement()
returns an HTML DOM element of the component,this.getState()
returns a state object.Our connector does the following:
-
Initializes the
slider
component of the jQuery UI library. Theslide()
function is invoked when the position of any drag handler changes. This function in turn invokes thevalueChanged()
connector method.valuedChanged()
is the method that we defined on the server side in theSliderServerComponent
class. -
Defines the
onStateChange()
function. It is called when the state object is changed on the server side.
-
To demonstrate how the component works, let’s create the Product
entity with three attributes:
-
name
of type String -
minDiscount
of type Double -
maxDiscount
of type Double
Generate standard screens for the entity. Ensure that the value of the In module field is Web Module
.
The slider
component will set minimal and maximum discount values of a product.
Open the product-edit.xml
file. Make minDiscount
and maxDiscount
fields not editable by adding the editable="false"
attribute to the corresponding elements. Then add the new custom slider
field to the fieldGroup
.
As a result, the XML descriptor of the editor screen should look as follows:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
caption="msg://editCaption"
class="com.company.jscomponent.web.product.ProductEdit"
datasource="productDs"
focusComponent="fieldGroup"
messagesPack="com.company.jscomponent.web.product">
<dsContext>
<datasource id="productDs"
class="com.company.jscomponent.entity.Product"
view="_local"/>
</dsContext>
<layout expand="windowActions"
spacing="true">
<fieldGroup id="fieldGroup"
datasource="productDs">
<column width="250px">
<field property="name"/>
<field property="minDiscount" editable="false"/>
<field property="maxDiscount" editable="false"/>
<field id="slider" custom="true"/>
</column>
</fieldGroup>
<frame id="windowActions"
screen="editWindowActions"/>
</layout>
</window>
Open the ProductEit.java
file. Replace its content with the following code:
package com.company.jscomponent.web.product;
import com.company.jscomponent.web.toolkit.ui.slider.SliderServerComponent;
import com.haulmont.cuba.gui.components.AbstractEditor;
import com.company.jscomponent.entity.Product;
import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.components.FieldGroup;
import com.haulmont.cuba.gui.components.VBoxLayout;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
import com.vaadin.ui.Layout;
import javax.inject.Inject;
public class ProductEdit extends AbstractEditor<Product> {
@Inject
private FieldGroup fieldGroup;
@Inject
private ComponentsFactory componentsFactory;
@Inject
private Datasource<Product> productDs;
@Override
protected void initNewItem(Product item) {
super.initNewItem(item);
item.setMinDiscount(15.0);
item.setMaxDiscount(70.0);
}
@Override
protected void postInit() {
super.postInit();
Component box = componentsFactory.createComponent(VBoxLayout.class);
Layout vBox = (Layout) WebComponentsHelper.unwrap(box);
SliderServerComponent slider = new SliderServerComponent();
slider.setValue(new double[]{getItem().getMinDiscount(), getItem().getMaxDiscount()});
slider.setMinValue(0);
slider.setMaxValue(100);
slider.setWidth("240px");
slider.setListener(newValue -> {
getItem().setMinDiscount(newValue[0]);
getItem().setMaxDiscount(newValue[1]);
});
vBox.addComponent(slider);
fieldGroup.getFieldNN("slider").setComponent(box);
}
}
The initNewItem()
method sets initial values for discounts of a new product.
Method init()
initializes the slider
custom field. It sets current, minimal and maximum values of the slider
and defines the value change listener. When the drag handler moves, a new value will be set to the corresponding field of the editable entity.
Start the application server and open the product editor screen. Changing the drop handler position must change the value of the text fields.