How to Convert Legacy Inputs to Forms

Create a Form Logic

  1. Create a form logic (defined as form in JSON) and name it after the calculation logic, using the _Form suffix.

  2. Create an element, for example Init, and set Calculation context to init.

  3. Link the new form logic to the pricing logic by using the Form logic field (formFormulaName in JSON).

Convert Static Inputs

If a calculation logic had inputs (line item pricing logics, dashboard logics, etc.), it included elements for input generation mode (previously syntax check mode). This logic now moves to a form logic, init mode (= Calculation context of an element).

  1. Remove all code inside the if (api.isInputGenerationExecution()) or if (api.isSyntaxCheck()) blocks of calculation logic elements. Move it to an element of the created form logic and set the Calculation context to init.

  2. Remove the code block in the element marking the end of input generation mode (typically called “AbortInputGeneration” or “AbortSyntaxCheck”):

    Groovy
    if (api.isInputGenerationExecution()) {
        api.abortCalculation()
    }
    

    or

    Groovy
    if (api.isSyntaxCheck()) {
        api.abortCalculation()
    }
    

    If no other code exists, remove this element entirely.

  3. In the form logic, replace api.inputBuilderFactory() calls with a variable form referencing FormInitAPI. The following methods are unsupported:

    • Replace calls to createConfiguratorInputBuilder(), api.configurator(), api.inlineConfigurator() with the configurator logic content - see the next section.

    • Remove createRowLayout() and createCollapseLayout(). These input types arranged inner inputs in a row or collapsible panel; now layouts handle this. Keep only the inner inputs.

    • Currently, createConfiguratorTable() is unsupported. Use createInputMatrix() instead. Special actions for Input matrix will be introduced in 17.1.

  4. Replace AbstractInputBuilder.getInput() calls with AbstractInputBuilder.buildFormInput()

Convert Configurator Logics

Move the creation of initial inputs from the configurator logic to the form logic element with Calculation context = init. Initial inputs are those generated without passing values to the configurator logic (as if def input = [:]).

Replace the call AbstractInputBuilder.addToConfiguratorEntry(ce) with AbstractInputBuilder.buildFormInput().

Convert Header Logic Inputs

The CLIC header logic creates or updates inputs for the header or line items.

Header inputs should now be populated by form logic.

Replace occurrences of

  • quoteProcessor.addOrUpdateInput(contextParameter)

  • quoteProcessor.addOrUpdateInput("ROOT", contextParameter)

  • cProcessor.addOrUpdateInput(contextParameter)

  • cProcessor.addOrUpdateInput("ROOT", contextParameter)

  • raProcessor.addOrUpdateInput(contextParameter)

  • raProcessor.addOrUpdateInput("ROOT", contextParameter)

  • customFormProcessor.addOrUpdateInput(contextParameter)

  • customFormProcessor.addOrUpdateInput("ROOT", contextParameter)

  • AbstractInputBuilder.buildContextParameter(ce)

Call the root element in form logic with Calculation context = init and create an input using the corresponding form input builder.

Adjust Option, Options and Radio Inputs

Inputs Option, Options, and Radio have value options provided via these methods:

  • OptionInputBuilder.setOptions(valueOptions)

  • api.option(inputName, valueOptions)

For static inputs, this can cause performance issues, especially in CLIC modules where quote objects become large because each line item stores all inputs and their value options.

Form logic allows value options to populate dynamically via asynchronous calls. This is recommended when there are more than 10 value options.

Create an element named, for example, ValueOptions in the form logic with Calculation context set to valueOptions. Implement the case of the switch for each input requiring value options:

Groovy
switch (form.sourceInputName()) {
    case "<input_name>":  // replace <input_name> with a real element name
        // place the code for populating the value options here (typically data queries)
    break
}

Row and Collapsible Inputs

The methods creating Row and Collapsible inputs

  • createRowLayout(inputName)

  • createCollapseLayout(inputName)

create a fake input that only contains inner inputs.

In forms, these fake inputs are unsupported; instead, layout objects serve this purpose. Consider this legacy code:

Groovy
api.inputBuilderFactory()
         .createRowLayout("Row")
         .addInput(
              api.inputBuilderFactory()
                  .createStringUserEntry("Width")
                  .buildContextParameter())
         .addInput(
              api.inputBuilderFactory()
                  .createStringUserEntry("Height")
                  .buildContextParameter())
          .getInput() // or addToConfiguratorEntry() or buildContextParameter()

The solution in forms is:

Groovy
def row = layout.createRow("MyRow")

form.createUserEntry("Width")
        .addToFormLayout(row)

form.createUserEntry("Height")
        .addToFormLayout(row)

layout.addChild(row)

Implement Actions

Identify which user interactions modify form inputs by changing properties, affecting value options, or adding or removing inputs.

Create an element in the form logic with Calculation context = action. For each action, implement the case of the switch for every input requiring value options:

Groovy
switch (form.sourceInputName()) {
    case "<input_name>":  // replace <input_name> with a real element name
        // place the code FormActionApi calls that modify the inputs of the form
    break
}