📌The HasValue interface
It is a general interface for UI elements with user-editable values, such as field components. It emits change events whenever the value changes, whether a user or a program makes the change.
It defines:
-
Various methods like getValue(), which returns the object's current value, and setReadOnly(), which sets the value of the current object to read-only.
- An event which fires when the value changes and a listener for the value change the event.
📌Helper Classes
Helper classes serve as a base class for custom fields. The helper classes below serve as a base class for creating custom components that show values and let users modify them. They are of three types, all used in different scenarios.
-
AbstractSinglePropertyField: An abstract field with a single element attribute. It is appropriate when the value is a property of the Component's sole element.
-
AbstractField: It is the most fundamental but also the most adaptable base class. There are numerous aspects to consider, yet it allows sophisticated use cases.
- AbstractCompositeField: It is identical to AbstractField, except that the base class is Composite rather than Component. It is appropriate when the value input component comprises numerous separate components.
Now that we have learned about the various helper classes let us discuss how we can create a component with a value using these.
💡Using a Single-element Property as the Value
The first way to create a component that has value is using single element property as value. Many components extend web components, which provide a property that holds the Component's value. When the value of property changes, it triggers a value-changed event.
When the property type is a string, integer, or Boolean, we extend AbstractSinglePropertyField and call its constructor with the name of the field, the default value, and whether or not it supports null values.
Consider the following PaperSlider component, which implements AbstractSinglePropertyField:
@Tag("paper-slider")
@NpmPackage(value = "@polymer/paper-slider", version = "3.0.1")
@JsModule("@polymer/paper-slider/paper-slider.js")
public class PaperSlider extends AbstractSinglePropertyField<PaperSlider, Integer>
{
public PaperSlider()
{
super("value", 0, false);
}
}

You can also try this code with Online Java Compiler
Run Code
Explanation
- AbstractSinglePropertyField's type parameters are: The type of the getSource() function in value-change events that have been triggered (PaperSlider).The kind of value (Integer).
- The clear() and isEmpty() functions utilise the default value of 0 by default. clear() returns true if the field value is empty, and isEmpty() returns true if the field value is empty.
Some Web Components have a Java type that is more appropriate than the type of the element attribute.
When modifying, reading, or writing the value to the element property, AbstractSinglePropertyField can use a converter.
The value attribute of < input type=" date ">, for example, is an ISO 8601-formatted string (YYYY-MM-DD). To choose a LocalDate, we may transform this into a DatePicker component.
💡Combining Properties Into One Value
In other circumstances, a component's value might be a combination of characteristics from one or more parts. In such circumstances, extending AbstractField is frequently the best answer.
When we extend AbstractField, we must deal with two value representations:
-
Presentation Value: The value shown to the user in the browser, such as element properties.
- Model Value: The value returned by the getValue() function.
Let us look at one example:
Begin by creating a DatePicker component that extends AbstractField and takes the default value as a parameter to its constructor.
@Tag("date-picker")
public class DatePicker extends AbstractField<DatePicker, LocalDate>
{
public DatePicker()
{
super(null);
}
}

You can also try this code with Online Java Compiler
Run Code
Now when we call the setValue method with a new value, AbstractField calls the setPresentationValue method with the new value, so we must implement the setPresentationValue:
@Override
protected void setPresentationValue(LocalDate val)
{
Element e = getElement();
if (val == null)
{
e.removeProperty("year");
e.removeProperty("month");
e.removeProperty("dayOfMonth");
}
else
{
e.setProperty("year", val.getYear());
e.setProperty("month", val.getMonthValue());
e.setProperty("dayOfMonth", val.getDayOfMonth());
}
}

You can also try this code with Online Java Compiler
Run Code
To handle browser-generated value changes, the Component must listen for suitable internal events and send a new value to the setModelValue(T value, boolean fromClient) function. AbstractField checks this to see if the specified value has changed and, if so, fires a value-change event to all listeners.
We must alter the constructor to declare each of the element's properties as synchronized and must add the identical property-change listener to each of them:
public DatePicker()
{
super(null);
setupProperty("year", "year-changed");
setupProperty("month", "month-changed");
setupProperty("dayOfMonth", "dayOfMonth-changed");
}
private void setupProperty(String name, String event)
{
Element e = getElement();
e.addPropertyChangeListener(name, event,this::propertyUpdated);
}

You can also try this code with Online Java Compiler
Run Code
Finally, use the property-change listener to generate a new LocalDate based on the element property values and provide it to setModelValue ().
private void propertyUpdated( PropertyChangeEvent event)
{
Element e = getElement();
int year = e.getProperty("year", -10);
int month = e.getProperty("month", -10);
int dayOfMonth = e.getProperty( "dayOfMonth", -10);
if (year != -10 && month != -10 && dayOfMonth != -10)
{
LocalDate newvalue = LocalDate.of(year, month, dayOfMonth);
setModelValue(newvalue, event.isUserOriginated());
}
}

You can also try this code with Online Java Compiler
Run Code
💡Creating Fields from Other Fields
The third way we can create field components. In this method, we use AbstractCompositeField helper class. It allows us to design a field component determined by the value of one or more internal fields.
Consider a student selection field that allows the user to select a course from a combo box and then another combo box to select a student from that course.
public class StudentField extends AbstractCompositeField<HorizontalLayout, StudentField, Student>
{
private ComboBox<Course> courseSelect = new ComboBox<>("Course");
private ComboBox<Student> studentSelect = new ComboBox<>("Student");
}

You can also try this code with Online Java Compiler
Run Code
Now in the constructor:
-Change the value of courseSelect() to update the entries in studentSelect ().
-The constructor assigns the field's value to the student picked in studentSelect().
public StudentField()
{
super(null);
courseSelect.setItems(StudentService.getCourses());
courseSelect.addValueChangeListener(event -> {
Course course = event.getValue();
studentSelect.setItems(StudentService.getStudents(course));
studentSelect.setEnabled(course != null);
});
studentSelect.addValueChangeListener(event ->
setModelValue(event.getValue(), true));
getContent().add(courseSelect, studentSelect);
}

You can also try this code with Online Java Compiler
Run Code
Next, use setPresentationValue() to change the combo boxes based on a specific student.
@Override
protected void setPresentationValue(Student student)
{
if (student == null)
{
courseSelect.clear();
}
else
{
courseSelect.setValue(course.getDepartment());
studentSelect.setValue(student);
}
}

You can also try this code with Online Java Compiler
Run Code
Frequently Asked Questions ❓
Are the type parameters for AbstractSinglePropertyField and AbstractField the same?
Yes, they are the same for both the helper classes.
Can AbstractField determine whether a new value is the same as the previous one?
AbstractField uses Objects.equals() by default to determine whether a new value is the same as the old value.
When should AbstractField ideally be used?
AbstractField should only be used with objects that have immutable values. If the original getValue() instance is updated and submitted to setModelValue() or setValue(), no value-change event is triggered ().
When we use AbstractField what are the two values that we must deal with?
Presentation and model value are the two values that we must deal with while using AbstractField.
📌Conclusion
Pretty much whatever we work within vaadin is a component. This article taught us about field components and how we can create them. After reading this blog, you must have gained some information about the field components. Wanna learn more about web technologies? Why not have a look at web technologies on Coding Ninjas Studio? Also, do you are looking for a set of questions which big tech giants ask during interviews then have a look on problems, interview experiences, and interview bundle which will help you in your placement preparations. Refer to other topics like computer networks, theory of computation and software engineering to expand your knowledge base. Do let us know if you come across any doubt.
Happy learning!