IForm is part of the Flutter SDK that allows you to create a form with a list of supported form components such as Input Text, Drop Down and more with validation feature provided for form validation. IForm is built on top of NUIForm and it act as the decoder before passing the readable form configuration to NUIForm.

  • Validation Rules - Programmers can configure the validation for each form component such as the min/max length as well as the string expression of a form field.

  • Customizable - The form is fully customizable from the arrangement and alignment of the form components to the colors of the borders and text.

Rendering The Form from JSON Configuration

As IForm is mainly to decode the form configuration JSON and process them into a readable set of form configuration for NUIForm, programmer can initialize the form with IFRenderEngineBuilder.

IFRenderEngine renderer = IFRenderEngineBuilder()
    .boyJson(yourJson)
    .textStyle(yourCustomizedTextStyle)
    .build();

Once you successfully parse the JSON to the IFRenderEngine, you can render the NUIForm through the renderForm() method with a set of optional listeners such as textChangeListener, buttonClickListener and itemSelectListener.

final form = renderer.renderForm(
    textChangeListener: (id, value, form){
        //TODO: text of a form component has changed
    },
    buttonClickListener: (id, clickType, form){
        //TODO: a button component has been clicked
    },
    itemSelectListener: (id, selection, selected, form){
        //TODO an item has been selected from drop down or check box
    }
);

With the NUIForm instance in place, you can now render the form as a widget by passing the form to a NUIFormContent widget.

return Container(
    child: NUIFormContent(form: form)
);

NUIForm Components

The list of supported NUIForm components can be found from http://dev.g-i.com.my/istudio/docs/dynamic-form/components/. Sample of a complete json can be found from http://dev.g-i.com.my/istudio/docs/dynamic-form/sample-json/.

Available Methods for NUIForm

MethodRemark
fillInValues()Fill in values for the components in the form
validate()Validate the form either quietly (without showing the error in UI) or normal validate
updateItem()Update any form component such as visibility or any other properties

Fill In Form Values

Programmers can fill in values into the form. As each form component's unique is the inpId, filling in values require the programmer to specify which form component to be updated.

form.fillInValues({
    "edtCountry": NUIFormValue(
        inpId: "edtCountry",
        value: NUIFromSelection(
            value: "Malaysia"
        )
    ),
    "edtState": NUIFormValue(
        inpId: "edtState",
        value: NUIFormSelection(
            value: "Selangor"
        )
    )
});

Validate the Form

Part of the configuration for the form is to have a validation rule for each of the form component, to configure whether the component is compulsory, or is there a length limitation on the form component. Once these validation rules are configured, calling the validate() from NUIForm will validate the form based on these validations and return a result of success if all the validations are successful or failed if one of the validation failed.

final validated = form.validate();

Update a Form Component

Programmers can update any of the form component after the form is rendered, such as changing the title of an input text or any other properties of the form component based on the component type. Below is an example of updating a NUIFTextItem component.

final updateItem = form.updateItem<NUIFTextItem>("edtCountry", (item){
   item.hint = "What are you from?";
   item.helperText = "Please fill this in";
});

A sample of NUIForm

//Defining your form styles
NUIFTextStyle myFontStyle(BuildContext context) => NUIFTextStyle(
  labelStyle: getFont(context, size: 16, color: accentBright, isBold: false),
  helperStyle: getFont(context, size: 12, color: accentBright, isBold: false),
  errorHelperStyle: getFont(context, size: 12, color: formErrorRed, isBold: false),
  border: OutlineInputBorder(borderSide: BorderSide(color: getColor(context, textGray), width: 1)),
  focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: getColor(context, accentBright), width: 2)),
  errorBorder: OutlineInputBorder(borderSide: BorderSide(color: getColor(context, formErrorRed), width: 1)),
  errorFocusedBorder: OutlineInputBorder(borderSide: BorderSide(color: getColor(context, formErrorRed), width: 2)),
  design: NUIFTextDesign.BORDER,
  dense: true,
  cursor: NUIFTextCursor(color: getColor(context, accentBright), cursorWidth: 2),
  textStyle: getFont(context, size: 16, color: textDarkGray, isBold: false),
  hintStyle: getFont(context, size: 16, singleColor: getColor(context, textLightGray), isBold: false),
);
          
//Using the form as your widget
class YourFormContent extends StatefulWidget {
  @override
  _YourFormContentState createState() => _YourFormContentState();
}

class _YourFormContentState extends State<YourFormContent> {
  NUIForm form;

  @override
  void initState(){
    super.initState();
    //Always initialize your form in initState() and not in the build() method as you do not want your form to get refreshed everytime the widget is rebuilt
    form = NUIForm(
        allButtonClickListener: (inpId, clickType, form){
          
        },
        allTextChangeListener: (inpId, value, form){
          
        },
        allItemSelectListener: (inpId, selection, selected, form){
          
        },
        item: NUIFColumnItem(inpId: "lytMyProfile", divider: 20, items: [
          NUIFTextItem(
            controller: TextEditingController(text: ""),
            inpId: "edtName",
            label: getString('formProfileNameLabel'),
            maskedInputType: NUIFTextInputType.NAME,
            minLength: 5,
            style: myFontStyle(context),
          ),
          NUIFTextItem(
            controller: TextEditingController(text: ""),
            inpId: "edtDateofBirth",
            hint: "Date of birth",
            label: getString('formProfileDateofBirthLabel'),
            style: myFontStyle(context),
            validateOnChange: true,
            maskedInputType: NUIFTextInputType.DATE,
            suffixIcon:
            Icon(Icons.event_note, color: getColor(context, accentBright)),
          ),
          NUIFDropdownItem(
            inpId: "spnGender",
            selections: [GenderSelection("Male"), GenderSelection("Female")],
            label: "Gender",
            style: myFontStyle(context),
          ),
        ])
    );
  }

  void extractFormValues(){
    Map<String, NUIFormValue> values = form.extractValues();
    final name = values["edtName"].value.value; //This is your name input from the form
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: NUIFormContent(
        form: form,
      ),
    );
  }
}

A sample of NUIForm from a JSON configuration

A sample of JSON form configuration would be like below. The properties of the form component are configured in the JSON configuration itself such as the id, caption and more.

{
    "jsLogic": "",
    "inputVerticalSpacing": 10,
    "inputs": [
        {
            "inpId": "txtAft",
            "caption": "Aft (m)",
            "compulsory": true,
            "show": true,
            "validateErrMsg": "Please enter a Aft value",
            "layout": 2,
            "intLayout": null,
            "preferredWidth": null,
            "type": "IngSinglelineText",
            "inputAllowType" : 1005,
            "inputAllowRegularExpression": "any",
            "rightSpacing": 10,
            "topSpacing": null
        },
        {
            "inpId": "txtFore",
            "caption": "Fore (m)",
            "compulsory": true,
            "show": true,
            "validateErrMsg": "Please enter a Fore value",
            "layout": 2,
            "intLayout": null,
            "preferredWidth": null,
            "type": "IngSinglelineText",
            "inputAllowType" : 1005,
            "inputAllowRegularExpression": "any",
            "rightSpacing": 10,
            "topSpacing": null
        },
        {
            "inpId": "txtTrim",
            "caption": "Trim (m)",
            "compulsory": true,
            "show": true,
            "readOnly": true,
            "validateErrMsg": "Please enter a Trim value",
            "layout": 2,
            "intLayout": null,
            "preferredWidth": null,
            "type": "IngSinglelineText",
            "inputAllowType" : 1005,
            "inputAllowRegularExpression": "any",
            "rightSpacing": 10,
            "topSpacing": null
        },
        {
            "inpId": "txtDate",
            "caption": "Date",
            "compulsory": true,
            "show": true,
            "validateErrMsg": "Please enter a Date value",
            "layout": 3,
            "intLayout": null,
            "preferredWidth": null,
            "type": "IngDatePicker",
            "dateTimeDisplayFormat": "dd MMM yyyy",
            "rightSpacing": null,
            "topSpacing": null
        }
    ]
}

After you have configured your form in the JSON, you can then later decode the JSON configuration into a NUIForm instance using the IFRenderEngineBuilder.

class YourFormContent extends StatefulWidget {
  @override
  _YourFormContentState createState() => _YourFormContentState();
}

class _YourFormContentState extends State<YourFormContent> {
  NUIForm form;
  IFRenderEngine renderer;

  @override
  void initState(){
    super.initState();
    renderer = IFRenderEngineBuilder()
        .bodyJson(yourJSONConfig)
        .textStyle(myFontStyle(context))
        .build();

    form = renderer.renderForm(
        buttonClickListener: (inpId, clickType, form){

        },
        textChangeListener: (inpId, value, form){

        },
        itemSelectListener: (inpId, selection, selected, form){

        }
    );
  }

  void extractFormValues(){
    Map<String, NUIFormValue> values = form.extractValues();
    final aftValue = values["txtAft"].value.value; //This is your name input from the form
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: NUIFormContent(
        form: form,
      ),
    );
  }
}

Libraries

nui_form
nuif_button
nuif_checkbox
nuif_checkgroup
nuif_column
nuif_custom
nuif_dropdown
nuif_form_component
nuif_list
nuif_models
nuif_radio
nuif_row
nuif_text