Drop Downs and Defaults

Invoking an action whose parameters are primitives or values (int, date, string etc) is simple: the user can just type in or use a date picker. Invoking an action with a parameter of reference type (such as Customer or Order) requires the viewer to provide some mechanism by which the end-user can select the relevant instance.

If the list of available options is fixed then the developer can provided a list a choices…​() supporting method (for either and action parameter or when editing a property). These are rendered in a drop-down.

If the list of available options is much larger, then the developer can use an autoComplete…​() supporting method. The user user enters a few characters and this is used to search for matching reference(s), again rendered in a drop-down.

Similarly, when invoking an action, there may well be suitable defaults for the action arguments. For example, if placing an Order then — even if the Product argument might not have a sensible default — the quantity argument could reasonably be defaulted to 1. Or, the Product might indeed have a default, say the product previously placed by this user. The developer indicates this using a default…​() supporting method.

Choices and Default

For example, choices for a property are specified using:

import lombok.Getter;
import lombok.Setter;

@Property(editing = Editing.ENABLED)                    (1)
@Getter @Setter
private String paymentMethod;

public List<String> choicesPaymentMethod() {            (2)
    return Arrays.asList("Visa", "Mastercard", "Amex");
}
1 If required; properties are by default disabled globally.
2 Note the "choices" prefix and the suffix matching up with the getter. The method must return a collection of the same type as the property.

For an action the choices and a suitable default method would be:

public Order changePaymentMethod(String paymentMethod) {
    setPaymentMethod(paymentMethod);
    return this;
}

public List<String> choices0ChangePaymentMethod() {         (1)
    return Arrays.asList("Visa", "Mastercard", "Amex");
}
public String default0ChangePaymentMethod() {               (2)
    return getPaymentMethod();                              (3)
}
1 "choices" prefix, N-th param, suffix matches up with the action’s name.
Returns a collection of the same type as the parameter.
2 "default" prefix, N-th param, the suffix matches up with the action’s name.
Returns object of same type as parameter.
3 Common idiom to return the current value of an property of the object.

AutoComplete

The autocomplete is similar to choices, but accepts a string parameter, to search for matching results. A property for example might have:

@Property(editing = Editing.ENABLED)                        (1)
@Getter @Setter
private Product product;

public List<Product> autoCompleteProduct(                   (2)
                        @MinLength(2) String search) {      (3)
    return productRepository.findByReferenceOrName(search);
}
1 If required; properties are by default disabled globally.
2 "autoComplete" prefix, suffix matches property name.
Returns a collection of the property’s type.
3 The @MinLength(…​) annotation indicates the minimum number of characters that must be entered before a search is initiated.

Actions are very similar:

public Order changeProduct(Product product) {
    setProduct(product);
    return this;
}

public List<Product> autoComplete0Product(                  (1)
                        @MinLength(2) String search) {
    return productRepository.findByReferenceOrName(search);
}
1 "autoComplete" prefix, N-th param, suffix matches action name.
Returns a collection of the parameters type.

An autoComplete method can be used in conjunction with a default method, but it doesn’t make sense to provide both an autoComplete and a choices method.

"Globally" defined drop-downs

Very often the set of available choices depends on the data type of the property/action parameter, rather than the individual property/parameter itself. And similarly the algorithm to search for references again may well depend only on that reference type.

In the case of choices, annotating a class as "bounded" (as in a "bounded" or fixed number of instances) means that a choices drop-down will automatically be defined. For example:

@DomainObject(
    bounded = true
)
public class Product { /* ... */ }

For more on this, see @DomainObject#bounding.

Or, if the data type is an enum, then a drop-down will be provided automatically. A payment method is a good example of this:

public enum PaymentMethod {
    VISA, MASTERCARD, AMEX;
}

Something similar can be achieved for autoComplete. Here the domain object indicates a repository query to execute. For example:

@DomainObject(
    autoCompleteRepository = Customers.class,
    autoCompleteMethod = "findByReferenceOrName"
)
public class Customer { /* ... */ }

with:

@DomainService(nature = NatureOfService.VIEW)
public class Customers {
    @Action(semantics=SemanticsOf.SAFE)
    public List<Customer> findByReferenceOrName(@MinLength(3) String refOrName) {
        ...
    }
}

For more on this, see @DomainObject#autoCompleteRepository.

There’s no need for the nominated method to be an actual action; any method of any domain service will do, so long as it accepts a string and returns the correct list.

Multi-select action parameters

As well as scalar values, action parameters can also be collections. For this to be valid, a choices or autoComplete supporting method must be provided.

For example, suppose we want to "tag" or "label" an object:

public StoryCard tag(List<Tag> tags) {
    getTags().addAll(tags);
}

public List<Tag> autoCompleteTag(@MinLength(1) search) {
    return tagRepository.findByName(search);
}

If the action has been associated with a collection, using @Action#associateWith(), then the collection can be used to provide a list of candidate values.

The Web UI (Wicket viewer) handles this by rendering checkboxes against the associated collection; the user can select/deselect these checkboxes and the selected items are taken as the values for the multi-select action.

Dependent choices for action parameters

For action it is also possible (in a limited form) to define dependencies between parameters. Specifically, if one parameter is a drop-down choice, then other drop-down choices can be derived from it.

A good example is a category/sub-category:

public ToDoItem categorize(
            Category category,
            Subcategory subcategory) {
    setCategory(category);
    setSubcategory(subcategory);
}

public List<Category> choices0Categorize() {
    return categoryRepository.allCategories();
}
public List<Subcategory> choices1Categorize(        (1)
                                Category category) {
    return subcategoryRepository.findBy(category);
}
1 Returns a list of choices for the 2nd parameter based on the argument provided for the first.

p