Model Form Dialogs

Hi there!

In our A12 project we have the customer requirement to create a new document out of a detail form view. Here is the concrete example:

  • Given: an overview model with a list of medical examinations.
  • The user selects one examination, the detail view is shown.
  • Inside the detail form a button is added called “Add Doctor”.

What I want here is a modal dialog that opens a new “doctor” form model to create a new doctor and is added to a combobox inside the parent form so that the user can immediately select the newly created doctor for the examination.

I tried a lot getting this to work (with heavily usage of Claude) but gave up in the end. It seems A12 is not designed for this use-case or did I miss something? The use case seem pretty common to me, so I wonder: Did I do something wrong? You have any code pointers for me or existing solutions? And if not, is that topic on the roadmap?

Hi,

There are multiple approaches to achieve this.

One key aspect in all of them is to use the modal region, which comes built-in whith the client and allows displaying anything in a modal overlay above the rest of the application.

For this, the Application Model needs to be configured in such a way that when the “add doctor” activity was created from the examination detail, a scene in the Application Model is matched that renders the “add doctor” View inside the modal region.

here is the content of a reduced example app model, showing this in principal:

{
  "header": {
    "id": "ExaminationsAppModel",
    "modelType": "application",
    "modelVersion": "6.0.0",
    "locales": [
      {
        "code": "en"
      }
    ],
    "annotations": [
      {
        "name": "roles",
        "value": "modeler"
      }
    ],
    "modelReferences": []
  },
  "content": {
    "region": {
      "name": "APP",
      "layout": {
        "name": "ApplicationFrame"
      },
      "subRegions": [
        {
          "layout": {
            "name": "MasterDetail"
          },
          "name": "CONTENT"
        },
        {
          "layout": {
            "name": "Stack"
          },
          "name": "SIDEBAR"
        },
        {
          "layout": {
            "name": "Stack"
          },
          "name": "MODAL" // <-- Here the modal region is defined, as a subregion of the root region 'APP'
        }
      ]
    },
    "defaultRegion": [
      "CONTENT"  // by default, i.e. if not configured otherwise, views are displayed in the 'CONTENT' region, with the built-in MasterDetail region layout
    ],
    "modules": [
      {
        "name": "Examinations",
        "menu": {
          "name": "Examinations",
          "label": [
            {
              "locale": "en",
              "text": "Examinations"
            }
          ],
          "initialActivity": {
            "descriptor": {
              "module": "examinations"
            }
          }
        },
        "flows": [
          {
            "name": "ExaminationsFlow",
            "scenes": [
              {
                "sceneChange": {
                  "onEnter": [
                    {
                      "type": "VIEW_ADD",
                      "name": "OverviewEngine" // added to content region by default
                    }
                  ]
                },
                "name": "ExaminationsOverview",
                "description": "overview of all examinations",
                "matchConditions": [
                  {
                    "key": "module",
                    "mustEqual": "examinations"
                  },
                  {
                    "key": "instance",
                    "isSet": false
                  }
                ]
              },
              {
                "sceneChange": {
                  "onEnter": [
                    {
                      "type": "VIEW_ADD",
                      "name": "FormEngine" // added to content region by default
                    }
                  ]
                },
                "name": "ExaminationDetail",
                "description": "detail view of one examination",
                "priorScene": "ExaminationsOverview",
                "matchConditions": [
                  {
                    "key": "module",
                    "mustEqual": "examinations"
                  },
                  {
                    "key": "instance",
                    "isSet": true
                  }
                ]
              },
              {
                "sceneChange": {
                  "onEnter": [
                    {
                      "type": "VIEW_ADD",
                      "region": [
                        "MODAL"
                      ],
                      "name": "FormEngine" // added to modal region this time as configured above
                    }
                  ]
                },
                "name": "AddDoctorModal",
                "description": "detail view for creating a new doctor, shown in a modal",
                "priorScene": "ExaminationDetail",
                "matchConditions": [
                  {
                    "key": "module",
                    "mustEqual": "examinations"
                  },
                  {
                    "key": "instance",
                    "isSet": true
                  },
                  {
                    "key": "addDoctorModal",
                    "isSet": true
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

Note, that the equivalent is also possible with the experimental DynamicConfig programming api, that can replace the Application Model (if you use this in your application).

The two approaches I have in mind:

  1. Working with CDMs and the “create and link” feature using a child activity
    • Here you would have a CDM composing an Examination via a to-one relationship with a Doctor
    • Creating a new Doctor would happen via a CDM Child Activity, for which the Form Engine could be rendered in the ModalRegion, just as explained above.
    • In the examination form, the user could either select via a Dropdown Selection from existing doctors or use the “Add” Button next to the dropdown to create a new doctor in the child activity (modal).
    • The child activity is created automatically in this case by the cdm feature. You can model how the child activity descriptor should look like in the to-one “Binding” placed in your CDM based Examination form model. You need to align this descriptor with the match conditions in your application model (or dynamic config) for the modal scene.
    • But on saving the new doctor modal form, the doctor would already be linked to the examination
    • Documentation about this cdm child activity feature can be found here: GetA12 .
  2. Working with a regular relationship and a custom button event handler
    • There would be a relationship allowing to assing one of the existing doctors to the examination. This could be done via a relationship ui (aka “Binding”) in the examination form.
    • The “add new doctor” activity is created from the examination form using an event button with a specific event name, e.g. “createNewDoctorInModal”
    • The event button can be placed anywhere in the form via a button panel, or it is placed in the subheader / footer.
    • The event is handled by dispatching a client api ActivityActions.push action (use ActivityActions.create factory), that creates the “new doctor” activity with a descriptor, that matches the modal scene in the Application Model. For this the form engine dispatch configuration needs to be customized. See GetA12 . Alternatively but not recommended, use a custom middleware reacting to the event by creating the new activity.
    • When the user saves a new doctor, the modal is closed and we are back to the examination detail view, where the new doctor now is selectable from the Dropdown Selection. But it is not automatically linked then.
    • This might be closer to what you have described as a requirement

Hey @matthias-modular-brook ,

Composed Data Models (CDMs) support the Create+Link user flow you are envisioning.

You can create a CDM in the SME and add the Root Document Model (Examination_DM) and the Relationship with the Child Document (Doctor_DM) to it.

Based on this, you can a Form Model. In the Form Model Editor use drag&drop to drag the Relationship-Model-Element (ExaminationDoctor_Relationship) into the Form Model to create a Binding.

For more information see A12 Documentation: CDMs

Activate CDM Child Activities in the Binding to allow Adding (Create+Link) and Editing a linked Document. From this Form.

Then create the other Form Model for Doctor_FM. You might want to use Header Navigation Tabs or show only the neccessary/mandatory Fields to make the “Dialog” not too overwhelming.

You can then plug both together in the App Model, as @conrad-solid-stream wrote above.

With this, te Doctor is created AND linked to the Examination. They are persisted together, when the enduser submits the Examination Form. (The Doctor will also just be persisted, when the Examination is persisted.)

One thing I overlooked in my sketch of the 2. (non-cdm) approach:

The available candidates for the doctors in the examination are only loaded, when the examination detail is entered the first time. They aren’t reloaded automatically, when coming back from the “create doctor” modal.

To solve this, one could use a custom middleware, that reacts to ActivityActions.commit.done or ActivityActions.save.done actions, checks whether the actions are dispatched for the activities with the respective activity descriptor (using the ActivitySelectors.activityById and comparing the descriptor) and for a match dispatches an ActivityActions.reloadData action for the parent activity. The parent activity id can be found by using ActivitySelectors.activitiesByDescriptor and the respective parent activity descriptor.

Reloading the parent activity also reloads the candidates, so the new doctor should be listed in the Dropdown Selection within the examination form.