No Lookup fields within fieldgroup

Hello, I have the following XML:

<dsContext>
        <datasource id="reportDs"
                    class="com.company.flux.entity.Report"
                    view="report-view"/>
        <datasource id="portfolioDs"
                    allowCommit="false"
                    class="com.company.flux.entity.Portfolio"
                    view="_local"/>
    </dsContext>
    <layout expand="windowActions"
            spacing="true">
        <fieldGroup id="fieldGroup"
                    datasource="reportDs">
            <column>
                <field id="name"
                       width="250px"/>
                <field id="portfolio"
                       width="250px"/>
                <field id="fileFormat"
                       width="250px"/>

Now, I would like to make the field portfolio a lookup field (so that users can choose from a list of portfolios).
So within the XML, I change the field to be:

<lookupField datasource="portfolioDs" property="portfolioCode" />

When I click Apply and go to the Layout tab, the portfolio field has disappeared.
So if I change the datasource to be a collectionDataSource, now from the Layout -> Properties, I can select the portfolioDs as my Collection data source. However, on the screen, itā€™s just a textbox and not a lookup component. If I change it to a lookupField, the portfolio field disappears upon pressing ā€œApplyā€.

Hello, Francis!
To make the ā€œportfolioā€ field a lookup field, you need to add the attribute optionsDatasource.
Here is the quote of the documentation:
optionsDatasource specifies a name of a data source, used to create a list of options. You can specify this attribute for a field connected to a reference entity attribute. By default, the selection of a related entity is made through a lookup screen. If optionsDatasource is specified, you can select the related entity from a drop-down list of options. Actually, specifying optionsDatasource will lead to the fact that LookupPickerField will be used in the field instead of PickerField.

Here is the example of XML:


<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        class="com.haulmont.sampler.gui.components.fieldgroup.simple.SimpleFieldGroupFrame">
    <dsContext>
        <datasource id="orderDs"
                    class="com.haulmont.sampler.entity.Order"
                    view="order-with-customer"/>
        <collectionDatasource id="customersDs"
                              class="com.haulmont.sampler.entity.Customer"
                              view="_minimal">
            <query>
                <![CDATA[select e from sampler$Customer e]]>
            </query>
        </collectionDatasource>
    </dsContext>
    <layout>
        <hbox spacing="true">
            <fieldGroup datasource="orderDs">
                <field id="date"/>
                <field id="customer" optionsDatasource="customersDs"/>
                <field id="amount"/>
                <field id="description"/>
            </fieldGroup>
            <button align="MIDDLE_LEFT"
                    caption="Show Order"
                    invoke="showOrder"/>
        </hbox>
    </layout>
</window>
1 Like

hi,
here is a running example of the lookup field:
The orders detail view has a property ā€œcustomerā€ (see here). The View definition of the order looks like this.
Actually you donā€™t even need to use a lookupField, just use a field tag insteadā€¦ Just make sure your report-view contains the relationship to the portfolio.
Bye,
Mario

Thanks it worked now.

This needs to be revisited. It doesnā€™t work as described in the documentation. I should be able to place an ā€˜optionsDatasourceā€™ on a field inside of a fieldGroup, and according to the documentation it will automatically use a LookupField (drop down), instead of a LookupPickerField (selection screen).

When I try to do this, I get a ā€˜datasource not foundā€™ exception.

Here is my view:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://editorCaption"
        class="com.company.grocery.web.store.StoreEdit"
        datasource="storeDs"
        focusComponent="fieldGroup"
        messagesPack="com.company.grocery.web.store">
    <dsContext>
        <datasource id="storeDs"
                    class="com.company.grocery.entity.Store"
                    view="store-view"/>
        <datasource id="zoneDs"
                    class="com.company.grocery.entity.Zone"
                    view="_local"/>
    </dsContext>
    <dialogMode height="600"
                width="800"/>
    <layout expand="windowActions"
            spacing="true">
        <fieldGroup id="fieldGroup"
                    datasource="storeDs">
            <column width="250px">
                <field property="storeNumber"/>
                <field property="name"/>
                <field optionsDatasource="zoneDs"
                       property="zone"/>
            </column>
        </fieldGroup>
        <frame id="windowActions"
               screen="editWindowActions"/>
    </layout>
</window>

and here is the exception:

com.haulmont.cuba.gui.GuiDevelopmentException: Options datasource zoneDs not found for field zone, frameId=grocery$Store.edit
	at com.haulmont.cuba.gui.xml.layout.loaders.FieldGroupLoader.loadField(FieldGroupLoader.java:358)
	at com.haulmont.cuba.gui.xml.layout.loaders.FieldGroupLoader.loadFields(FieldGroupLoader.java:294)
	at com.haulmont.cuba.gui.xml.layout.loaders.FieldGroupLoader.loadFields(FieldGroupLoader.java:284)
	at com.haulmont.cuba.gui.xml.layout.loaders.FieldGroupLoader.loadComponent(FieldGroupLoader.java:138)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponents(ContainerLoader.java:37)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponentsAndExpand(ContainerLoader.java:89)
	at com.haulmont.cuba.gui.xml.layout.loaders.WindowLoader.loadComponent(WindowLoader.java:80)
	at com.haulmont.cuba.gui.WindowManager.createWindow(WindowManager.java:575)
	at com.haulmont.cuba.gui.WindowManager.openEditor(WindowManager.java:869)
	at com.haulmont.cuba.web.WebWindowManager.openEditor(WebWindowManager.java:178)
	at com.haulmont.cuba.gui.components.WindowDelegate.openEditor(WindowDelegate.java:258)
	at com.haulmont.cuba.web.gui.WebWindow.openEditor(WebWindow.java:487)
	at com.haulmont.cuba.gui.components.actions.CreateAction.internalOpenEditor(CreateAction.java:305)
	at com.haulmont.cuba.gui.components.actions.CreateAction.actionPerform(CreateAction.java:265)
	at com.haulmont.cuba.web.gui.components.WebButton.performAction(WebButton.java:45)
	at com.haulmont.cuba.web.gui.components.WebButton.lambda$new$61446b05$1(WebButton.java:37)
	at sun.reflect.GeneratedMethodAccessor181.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:200)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:163)
	at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1037)
	at com.vaadin.ui.Button.fireClick(Button.java:377)
	at com.haulmont.cuba.web.toolkit.ui.CubaButton.fireClick(CubaButton.java:54)
	at com.vaadin.ui.Button$1.click(Button.java:54)
	at sun.reflect.GeneratedMethodAccessor197.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)

Also, this is on version 6.9.1.

I figured out the problem. The Datasource must be an instance of CollectionDatasource. The error message in this case is incorrect, since it find its, then skips it (because it is of not the correct type), so then it canā€™t find itā€¦

   protected CollectionDatasource findDatasourceRecursively(DsContext dsContext, String dsName) {
        if (dsContext == null) {
            return null;
        }


        Datasource datasource = dsContext.get(dsName);
        if (datasource != null && datasource instanceof CollectionDatasource) {
            return (CollectionDatasource) datasource;
        } else {
            if (dsContext.getParent() != null) {
                return findDatasourceRecursively(dsContext.getParent(), dsName);
            } else {
                return null;
            }
        }
    }

...
        CollectionDatasource optionsDs = null;
        String optDsName = element.attributeValue("optionsDatasource");
        if (StringUtils.isNotBlank(optDsName)) {
            DsContext dsContext = getContext().getFrame().getDsContext();
            optionsDs = findDatasourceRecursively(dsContext, optDsName);
            if (optionsDs == null) {
                throw new GuiDevelopmentException(String.format("Options datasource %s not found for field %s", optDsName, id)
                        , context.getFullFrameId());
            }
        }