Here's how to implement a server-backed External Enumeration! Comments?

I have found the documentation about External Enumerations a bit lacking (to say the least).
When you search for it in the docs, there are a couple of sections at different places, but no comprehensive example that shows how everything ties together. (BTW: The few code snippets that are presented all lack import statements, which is a problem especially when such generic class names like “Config” are used in the code.)

The following is what I figured out and stitched together.
Comments are very welcome: Is there a better way to do this?

For example, I guess, if the referenced data changes only very rarely, then it could be loaded just once when the application starts. (This solution loads the data whenever the form that uses the External Enumeration is rendered.)

I took care to implement it in the standard A12 Project Template of A12 (version 202506.0.1), so that I can show only the changes and all the changes needed to add a specific external enumeration:

The default project template shows a overview and form for a Person document model.
One of the fields is “Nationality” which is just a string:
We reconfigure that to use an auto-complete that shows data loaded from the server:

Add endpoint to server to retrieve a list of countries
Since this is not the interesting part for this topic, let’s take an easy way.

  • Create a file countries.json that holds the data
  • Put it in server/src/main/resources/public/api/.
    Spring Boot will make all files in public accessible to the client.
    The api subfolder is what webpack proxies to the server when the client is started locally.

Now the list of countries can be loaded from http://localhost:8081/api/countries.json
See attachment for the file.

Re-configure the form model
The form engine needs to know that Nationality gets populated via an external enumeration.
See A12 docs at GetA12
(under “Modeling → UI Modeling → Form Modeling”, then “Editors For Model Elements → Controls → String Type”, section “External Enumeration”)
We need to configure the “Source URL” for the external enumeration. This is not really (directly) used as a URL, but just serves as a key to identity a specific external enumeration.

Create a react component for the Person form
Create a react component in client/src/components/PersonFormEngineView.tsx
This component

  • wraps the FormEngine
  • adds state that holds the countries
  • uses an effect to populate that state
  • defines an IExternalEnumerationProvider to return the enum values when asked for an External Enumeration with the “Source URL” that is defined in the form model.

Complete source code is attached (see bottom of this post), but here’s the core:


import React, {ReactElement} from "react";

import {ReadonlyObjectMap} from "@com.mgmtp.a12.formengine/formengine-core/lib/models";
import {View} from "@com.mgmtp.a12.client/client-core/lib/core/view";
import IExternalEnumerationProvider
    from "@com.mgmtp.a12.formengine/formengine-core/lib/back-end/services/external-enumeration-provider";
import {DocumentModel} from "@com.mgmtp.a12.kernel/kernel-md-facade";
import {CRUDViews} from "@com.mgmtp.a12.crud/crud-core";
import {ConnectorLocator, RestServerConnector} from "@com.mgmtp.a12.utils/utils-connector/lib/main";

...

/**
 * Wraps the form engine view and adds country data as state
 */
export default function PersonFormEngineView(props: View): ReactElement {
    const [countries, setCountries] = React.useState<ReadonlyObjectMap<{ [key: string]: string | undefined }>>({});

    // See Fetching data with Effects at https://react.dev/reference/react/useEffect#fetching-data-with-effects
    React.useEffect(() => {
        let ignore = false;
        loadCountries()
            .then(countries => {
                    if (!ignore) {
                        setCountries(mapCountriesToExternalEnum(countries));
                    }
                }
            );
        return () => {
            ignore = true;
        };
    }, []);

    /**
     * Teach the form engine about our external enumeration.
     *
     * See A12 docs "Modeling -> UI Modeling -> Form Modeling"
     * then "Editors For Model Elements -> Controls -> String Type", section "External Enumeration"
     * https://geta12.com/#/docs/2025.06/ext0/sme/sme-fm-ba-docs%23txt:details:external-enumeration
     *
     * @param source the "sourceUrl" defined in the form model, this is not really a URL, but a key meant to identify
     * this specific external enumeration
     */
    const externalEnumerationProvider: IExternalEnumerationProvider = (
        source: string
    ): DocumentModel.ReadonlyObjectMap<{ [key: string]: string | undefined }> => {
        switch (source) {
            case "countries": {
                return countries;
            }
            default:
                throw new Error("unknown external enumeration source: " + source);
        }
    };

    return <CRUDViews.FormEngineView {...props} externalEnumerationProvider={externalEnumerationProvider}/>;
}

Configure that react component to be used
Reconfigure the application model json to use a component “PersonFormEngine” (instead of just “FormEngine”):


To resolve that name to the actual react component we have to extend the viewProvider.tsx:

And Bob’s your uncle.

// EDIT: Had to use *.txt extension for the *.tsx files to be able to upload the code, just strip that suffix again:
PersonFormEngineView.tsx.txt (3.5 KB)
countries.json (6.9 KB)

3 Likes