-
Notifications
You must be signed in to change notification settings - Fork 83
Description
Description
Integrate Signals API into Vaadin Components through the base Component class, mix-in HasXyz interfaces or by adding direct methods to Flow Components to provide a way of building reactive UI with Java.
Tier
Free
License
Apache 2.0
Motivation
Background
Vaadin 24.8, 24.9 have shipped the base Signals class hierarchy and helpers in ComponentEffect.
Vaadin 25.0 has added Element-level binding methods and helpers in ElementEffect.
Vaadin 25.1 is now aims to fully integrate Signal API into Vaadin Flow Components, so that developers can us this way of building UI as a primary.
Problem
Overall problem: It is common in Vaadin to explicitly handle UI state change by users in the event listeners, maintain clean ups and set the UI state explicitly through the component's methods. This may lead to a boiler-plate code that makes the view classes be unreadable and hard-maintained. Signals on the other hand may simplify the UI development by implicitly handling the state change no matter what kind of source did this - single user event, multi-user events or asynchronous background event, and implicitly handling the component UI attached/detached state.
Signal API current status: Whereas the Signal and related classes are available, it's not yet possible to code the reactive UIs using signals and without using existing low-level Element API, explicit effect functions and defining addValueChangeListener(), nor there is a way of binding signals to a form.
Solution
Signals integration to Vaadin Components would include:
- Signal binding methods to
Componentclass and mix-in interfaces for commonly used component properties (visible, enabled, value) - Component-specific signal binding methods (e.g.
setHelperText) - Two-way signal binding for standalone field components and forms.
- Ensure Signal API is serializable.
This in the end means the component provide bind methods for the component features for the following kind of bindings
- one way binding (e.g. text)
- two-way binding (e.g. value)
- callbacks that use signal as a state (e.g. item label generator),
and theBinderAPI is adjusted/extended so it's features can useSignaland benefit from two-way bindings.
As an example of how the code may look like when using signals, guess the products price calculator add VAT to the base price and updates all product cards:
Example with the value change listeners:
NumberField vatField = new NumberField("VAT %");
// 1. Value change listener explicitly added
Registration vatChangeRegistration = vatField.addValueChangeListener(event -> {
productCards.forEach(productCard -> {
String newPriceLine = getUpdatedPrice(event.getValue());
// 2. Product component explicitly updated with the new price
productCard.setPriceLine(newPriceLine);
});
});
// 3. Duplicated code that repeats the listener code for component initialization
productCards.forEach(productCard -> {
// initialize the UI nearly the same way
});
// 4. Manual cleanup on detaching
vatChangeRegistration.remove();Same example with signals:
// 3. State initialized once a signal is instantiated
ReferenceSignal<Double> vatSignal = new ReferenceSignal<>(24.0);
// 1. Two-way binding, no explicit listeners
// 4. No registration, signal is deactivated on detach
vatField.bindValue(vatSignal);
// Computed signal
Signal<String> priceWithVatText = vatSignal.map(this::getUpdatedPrice);
// 2. Bind computed signal to the product
productCards.forEach(productCard -> productCard.bindText(priceWithVatText));Requirements
-
ComponentandElementclasses shall implementvoid bindVisible(Signal<Boolean> visibleSignal)new methods.Componentdelegates toElementand has the same contract; -
HasEnabledmix-in andElementclass shall implementvoid bindEnabled(Signal<Boolean> enabledSignal)new methods.HasEnableddelegates toElementand has the same contract; -
HasTextmix-in interface shall implementvoid bindText(Signal<String> textSignal)new method and delegate to the same existing method inElement; -
HasValue<T>mix-in andElementshall implementvoid bindValue(WritableSignal<T> valueSignal)new methods. Note that this is a two-way binding that also updates the signal value when aValueChangeEventwould be fired. -
More requirements...
-
Documentation shall recommend using signals in all places where handling components/UI state is applicable.
-
Feature flag shall be removed.
Nice-to-haves, but may not fit into 25.1 schedule
- Helpers for debugging Signals
- Binding to items in
HasItemscomponents - Router integration
- Clustering
Risks, limitations and breaking changes
Risks
Limitations
Breaking changes
Out of scope
No response
Materials
No response
Metrics
No response
Pre-implementation checklist
- Estimated (estimate entered into Estimate custom field)
- Product Manager sign-off
- Engineering Manager sign-off
Pre-release checklist
- Documented (link to documentation provided in sub-issue or comment)
- UX/DX tests conducted and blockers addressed
- Approved for release by Product Manager
Security review
None
Metadata
Metadata
Assignees
Labels
Type
Projects
Status