The EntitySearchField is a powerful UI component for entity selection through text-based searching. It extends HintTextField and provides a search interface that triggers on ENTER key, displaying results based on the configured search criteria.

1. Overview

EntitySearchField provides:

  • Text-based entity searching with automatic result handling

  • Single or multi-entity selection

  • Customizable result selection UI (list, table, or custom)

  • Optional add/edit functionality for creating or modifying entities

  • Search progress indication (wait cursor or progress bar)

  • Automatic search on focus loss (optional)

  • Keyboard shortcuts for add/edit operations

2. Basic Usage

Creating a basic search field
    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider)
            .searchColumns(List.of(Customer.FIRSTNAME, Customer.EMAIL))
            .build();

    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .multiSelection()
            .columns(20)
            .build();

3. Search Behavior

The search field operates as follows:

  1. User types search text and presses ENTER

  2. If the search returns:

    • No results: A message dialog is shown

    • Single result: That entity is automatically selected

    • Multiple results: A selection dialog appears

Note
Multi-selection is the default mode for EntitySearchModel. The .singleSelection(false) call in examples is shown for clarity but is not required.

3.1. Single Selection

For selecting one entity at a time:

    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider).build();

    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .singleSelection()
            .build();

3.2. Multi-Selection

For selecting multiple entities (this is the default mode):

    EntitySearchModel searchModel = EntitySearchModel.builder(Track.TYPE, connectionProvider).build();

    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .multiSelection()
            .build();

4. Customization Options

4.1. Custom Selectors

The default selector uses a list for result selection. You can provide custom selectors:

Custom table selector
    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider).build();

    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .multiSelection()
            .selectorFactory(EntitySearchField::tableSelector)
            .build();

4.2. Add and Edit Controls

Enable inline entity creation and editing:

Search field with add/edit capabilities
    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider).build();
    SwingEntityEditModel editModel = new SwingEntityEditModel(Customer.TYPE, connectionProvider);

    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .singleSelection()
            .editPanel(() -> new CustomerEditPanel(editModel))
            .confirmAdd(true)     // Confirm before adding
            .confirmEdit(true)    // Confirm before editing
            .build();

    // Access controls
    searchField.addControl();   // INSERT key by default
    searchField.editControl();  // CTRL+INSERT by default

4.3. Search Indicators

Configure how search progress is displayed:

Progress bar indicator
    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider).build();

    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .multiSelection()
            .searchIndicator(SearchIndicator.PROGRESS_BAR)
            .build();

4.4. Field Configuration

Various field configurations
    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider).build();

    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .singleSelection()
            .columns(20)                      // Field width
            .upperCase(true)                  // Force uppercase
            .searchHintEnabled(true)          // Show "Search..." hint
            .searchOnFocusLost(true)          // Auto-search when focus lost
            .selectionToolTip(true)           // Show selection as tooltip
            .editable(false)                  // Make read-only
            .stringFactory(entity ->    // Custom display text
                    entity.get(Customer.LASTNAME) + " - " + entity.get(Customer.CITY))
            .separator(" | ")                 // Multi-selection separator
            .build();

5. Search Control

You can trigger searches programmatically:

Programmatic search control
    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider).build();
    EntitySearchField searchField = EntitySearchField.builder(searchModel)
            .multiSelection()
            .build();

    // Get search control
    Control searchControl = searchField.searchControl();

    // Use in toolbar or menu
    Controls.builder()
            .control(searchControl)
            .build();

6. Advanced Features

6.1. Component Value Integration

A EntitySearchField based ComponentValue can be created via buildValue():

Reactive search field
    EntitySearchModel searchModel = EntitySearchModel.builder(Customer.TYPE, connectionProvider).build();
    SwingEntityEditModel editModel = new SwingEntityEditModel(Invoice.TYPE, connectionProvider);

    ComponentValue<Entity, EntitySearchField> searchFieldValue =
            EntitySearchField.builder(searchModel)
                    .singleSelection()
                    .buildValue();

    EntitySearchField searchField = searchFieldValue.component();
    // React to selection changes
    searchField.model().selection().entities().addConsumer(selectedEntities ->
            System.out.println("Selected: " + selectedEntities));

    // Link to edit model
    editModel.editor().value(Invoice.CUSTOMER_FK).link(searchFieldValue);

6.2. Custom Edit Component Factory

Use custom search fields in edit panels:

Custom factory example from Chinook demo
class TrackEditComponentFactory extends DefaultEditComponentFactory<Entity, EntitySearchField> {

    @Override
    protected EntitySearchField.SingleSelectionBuilder searchField(
            ForeignKey foreignKey,
            EntityDefinition entityDefinition,
            EntitySearchModel searchModel) {
        return super.searchField(foreignKey, entityDefinition, searchModel)
                .selectorFactory(new TrackSelectorFactory());
    }
}

7. Configuration Properties

Table 1. EntitySearchField Configuration
Property Default Description

is.codion.swing.framework.ui.component.EntitySearchField.searchIndicator

WAIT_CURSOR

How to indicate ongoing searches (WAIT_CURSOR or PROGRESS_BAR)

8. Best Practices

  1. Provide Clear Search Columns: Configure the search model with appropriate searchable columns

  2. Consider Performance: Use result limits in the search model for large datasets

  3. Keyboard Support: Leverage the built-in keyboard shortcuts (INSERT for add, CTRL+INSERT for edit)

  4. Custom Selectors: Create custom selectors for complex selection scenarios

9. Common Pitfalls

9.1. Missing Search Configuration

Ensure the search model has searchable columns configured:

Proper search configuration
    EntitySearchModel model = EntitySearchModel.builder(Customer.TYPE, connectionProvider)
            .searchColumns(List.of(Customer.LASTNAME, Customer.EMAIL, Customer.PHONE))
            .build();