Data Binding & Data Providers

Connect UI components to data sources with providers and binding—clean, testable architecture.

Data Providers

Pluggable data sources that supply components with data on demand. Supports pagination, filtering, and sorting out of the box.

Data Binding

Bind UI fields directly to data models. Changes in the model update the UI, and user input flows back to the model automatically.

Dependency Injection

Inject services and data sources into pages and components. Keep business logic separate from presentation.

Lazy Loading

Load data only when needed. Data providers fetch pages of records on demand, reducing memory usage and improving startup time.

Pagination Support

Built-in pagination for large data sets. Components request only the data they need to display, with configurable page sizes.

Clean Architecture

Separate data access from UI logic. Data providers act as a clean boundary between your backend services and UI components.

Data Providers

Data providers connect your UI components to backend data sources. Components automatically refresh when data changes.

Java
// Define a data provider
public class UserDataProvider implements DataProvider<User>
{
    @Override
    public List<User> fetchData(int offset, int limit)
    {
        return userService.getUsers(offset, limit);
    }

    @Override
    public int getTotalCount()
    {
        return userService.getUserCount();
    }
}

// Use in a page
@Page("/users")
public class UsersPage extends HtmlPage
{
    @Override
    protected void createBody(Body body)
    {
        UserDataProvider provider = new UserDataProvider();

        // Grid automatically paginates and refreshes
        DataGrid grid = new DataGrid();
        grid.setDataProvider(provider);
        grid.addColumn("Name", User::getName);
        grid.addColumn("Email", User::getEmail);
        body.addElement(grid);
    }
}

Benefits

Automatic Pagination

Data providers handle pagination transparently. Components request data by offset and limit, and the provider fetches exactly what is needed from your backend.

Lazy Loading

Data is fetched on demand rather than all at once. This keeps memory usage low and startup times fast, even with millions of records in your database.

Separation of Concerns

Data access logic lives in providers, not in your pages. This makes your code easier to understand, maintain, and refactor as requirements change.

Testable Components

Because data providers are interfaces, you can easily mock them in unit tests. Test your UI logic independently of your database or API layer.

Reusable Providers

Write a data provider once and use it across multiple pages and components. Share the same data source between a grid, a chart, and a summary panel without duplicating code.