Skip to main content

Composite Components

Open in ChatGPT
23.06
Java API

The Composite component combines existing webforJ components into self-contained, reusable components with custom behavior. Use it to wrap internal webforJ components into reusable business logic units, reuse component patterns throughout your app, and combine multiple components without exposing implementation details.

A Composite component has a strong association with an underlying bound component. This gives you control over which methods and properties users can access, unlike traditional inheritance where everything is exposed.

If you need to integrate web components from another source, use specialized alternatives:

Usage

To define a Composite component, extend the Composite class and specify the type of component it manages. This becomes your bound component, which is the root container that holds your internal structure:

BasicComposite.java
public class BasicComposite extends Composite<FlexLayout> {

public BasicComposite() {
// Access the bound component to configure it
getBoundComponent()
.setDirection(FlexDirection.COLUMN)
.setSpacing("3px")
.add(new TextField(), new Button("Submit"));
}
}

The getBoundComponent() method provides access to your underlying component, allowing you to configure its properties, add child components, and manage its behavior directly.

The bound component can be any webforJ component or HTML element component. For flexible layouts, consider using FlexLayout or Div as your bound component.

Component Extension

Never extend Component or DwcComponent directly. Always use composition patterns with Composite to build custom components.

Override initBoundComponent() when you need greater flexibility in creating and managing the bound component, such as using parameterized constructors instead of the default no-argument constructor. Use this pattern when the bound component requires components to be passed to its constructor rather than added afterward.

CustomFormLayout.java
public class CustomFormLayout extends Composite<FlexLayout> {
private TextField nameField;
private TextField emailField;
private Button submitButton;

@Override
protected FlexLayout initBoundComponent() {
nameField = new TextField("Name");
emailField = new TextField("Email");
submitButton = new Button("Submit");

FlexLayout layout = new FlexLayout(nameField, emailField, submitButton);
layout.setDirection(FlexDirection.COLUMN);
layout.setSpacing("10px");

return layout;
}
}

Component lifecycle

webforJ handles all lifecycle management for Composite components automatically. By using the getBoundComponent() method, most custom behavior can be handled in the constructor, including adding child components, setting properties, basic layout setup, and event registration.

public class UserDashboard extends Composite<FlexLayout> {
private TextField searchField;
private Button searchButton;
private Div resultsContainer;

public UserDashboard() {
initializeComponents();
setupLayout();
configureEvents();
}

private void initializeComponents() {
searchField = new TextField("Search users...");
searchButton = new Button("Search");
resultsContainer = new Div();
}

private void setupLayout() {
FlexLayout searchRow = new FlexLayout(searchField, searchButton);
searchRow.setAlignment(FlexAlignment.CENTER);
searchRow.setSpacing("8px");

getBoundComponent()
.setDirection(FlexDirection.COLUMN)
.add(searchRow, resultsContainer);
}

private void configureEvents() {
searchButton.onClick(event -> performSearch());
}

private void performSearch() {
// Search logic here
}
}

If you have additional specific setup or cleanup requirements, you may need to use the optional lifecycle hooks onDidCreate() and onDidDestroy():

public class DataVisualizationPanel extends Composite<Div> {
private Interval refreshInterval;

@Override
protected void onDidCreate(Div container) {
// Initialize components that require DOM attachment
refreshInterval = new Interval(5.0, event -> updateData());
refreshInterval.start();
}

@Override
protected void onDidDestroy() {
// Cleanup resources
if (refreshInterval != null) {
refreshInterval.stop();
}
}

private void updateData() {
// Data update logic
}
}

If you need to perform any actions after the component is attached to the DOM, use the whenAttached() method:

InteractiveMap.java
public class InteractiveMap extends Composite<Div> {
public InteractiveMap() {
setupMapContainer();

whenAttached().thenAccept(component -> {
initializeMapLibrary();
loadMapData();
});
}
}

Example Composite component

The following example demonstrates a Todo app where each item is a Composite component consisting of a RadioButton styled as a switch and a Div with text:

Show Code

Example: Component grouping

Sometimes you may want to use a Composite to group related components together into a single unit, even when reusability isn't the main concern:

Show Code