4.3.2. Passing Parameters to a Screen

Passing parameters from one screen to another is one of the most common tasks in UI development. Let’s consider this task taking an "order management" application as an example.

Opening screen with openWindow

Parameters can be passed by providing them in a map to openWindow(), openLookup() or openEditor() methods. They will be available in the opened screen as a map in the init() method and individually if you inject them with the @WindowParam annotation.

Suppose we want to filter the products in the Product browser passing some parameters from the Order editor.

  • OrderEdit screen contains the addOrderLine() method which is invoked by addOrderLine action. The method opens a products lookup screen passing two parameters to it:

    • the currently selected customer,

    • the list of already added products.

      After a user selects a product, the QuantityDialog screen is opened for entering product quantity. When the user closes it, a new instance of OrderLine entity is created and added to the table.

      openLookup("sample$Product.browse",
              items -> {
                  if (!items.isEmpty()) {
                      openQuantityDialog((Product) items.iterator().next());
                  }
              },
              WindowManager.OpenType.THIS_TAB,
              ParamsMap.of(
                      "customer", getItem().getCustomer(),
                      "added", orderLinesDs.getItems().stream()
                                              .map(line -> line.getProduct().getId())
                                              .collect(Collectors.toList())
              )
      );
  • ProductBrowse screen modifies its datasource query depending on passed customer. If a customer is provided, the table shows only products for this customer and those without reference to a customer. The parameters are injected in the screen controller using the @WindowParam annotation:

    @WindowParam
    private Customer customer;
    
    @Override
    public void init(Map<String, Object> params) {
        if (customer != null) {
            productsDs.setQuery(
                    "select e from sample$Product e left join e.customer c " +
                    "where c.id = :param$customer or c is null");
        }
    }

    When the product browser is opened for looking up items to be used as order lines, it also creates and applies programmatically a filter to show only products not yet added to the order.

    Tip

    Filters should be added in the ready() method, as at the moment of the init() method invocation filters are not yet initialized.

    @WindowParam
    private List<UUID> added;
    
    @Override
    public void ready() {
        if (added != null && !added.isEmpty()) {
            FilterEntity filterEntity = metadata.create(FilterEntity.class);
            filterEntity.setName("Not added yet");
            filterEntity.setXml("<filter>\n" +
                    " <and>\n" +
                    " <c name=\"id\" class=\"java.util.UUID\" inExpr=\"true\" hidden=\"true\" operatorType=\"NOT_IN\" width=\"1\" type=\"PROPERTY\">" +
                    " <![CDATA[((e.id not in :component$filter.id_list) or (e.id is null)) ]]>\n" +
                    " <param name=\"component$filter.id_list\" javaClass=\"java.util.UUID\">NULL</param>\n" +
                    " </c>\n" +
                    " </and>\n" +
                    "</filter>");
            filter.setFilterEntity(filterEntity);
            filter.setParamValue("id_list", added);
            filter.apply(true);
        }
    }

    The contents of the FilterEntity.xml attribute can be taken from a filter created at runtime: go to Entity Inspector, find the created filter which is stored as an instance of the sec$Filter entity and copy its XML.

Opening screen from a PickerField

The PickerField component and its ancestors can also pass parameters to opened screens. The parameters should be defined for the PickerField actions: LookupAction or OpenAction.

Suppose we want to customize the caption of the Customer browser if it is opened from a PickerField in the Product editor.

  • In the ProductEdit screen we set the parameters for the PickerField LookupAction using its setLookupScreenParams() method:

    public class ProductEdit extends AbstractEditor<Product> {
    
        @Named("fieldGroup.customer")
        private PickerField customerField;
    
        @Override
        protected void postInit() {
            customerField.getLookupAction().setLookupScreenParams(ParamsMap.of("product", getItem()));
        }
    }
  • Then, we inject the passed parameter in the CustomerBrowse screen:

    @WindowParam
    private Product product;
    
    @Override
    public void init(Map<String, Object> params) {
        if (product != null && product.getName() != null) {
            getFrame().setCaption("Select a customer for " + product.getName());
        }
    }

Now, if the customer browser is opened from the product editor, we will know exactly which product it was.