Control focus lost after selecting a drop-down value... for dynamically generated drop-downs.

I have a data-driven interface... An array of some data is passed to the interface, a foreach loop renders controls on the screen (including a drop-down list) based on the input data.

The problem I see is the control focus is lost whenever a value is selected from a drop-down list.  There are two "flavors" of this issue.  First, if I use the mouse to select a value from the drop-down, the control focus (which should be on the drop-down) seems to revert to the top of the page.  Pressing <tab> focuses on controls at the top of the page.  Second, if I use the keyboard, arrow down to the choice, then press <tab> to select the value and move to the next control, the control focuses on the next control for an instant then it goes away.  Pressing <tab> at this point places the focus on the drop-down control I just used.  Third, if I use the keyboard and press enter to select the drop-down item, it behaves as if I were using the mouse.... control focus is lost and <tab> focuses on a control at the top of the page.

This creates accessibility problems for keyboard-only users.  They have to tab through the page after selecting from drop down lists.

Now, if I skip the a!foreach() and just hard-code each of the sets of controls.  The interface behaves as I would expect.  There are no serious control focus issues.  But I need to be able to handle an unknown number of incoming data elements.  (No, a grid will not work.)

It appears the foreach is causing the focus to be lost when a drop-down value changes.  Is this normal behavior?  Is there any way to keep the focus where it should be when using dynamically generated controls?

Thank you.

Here is the "parent" interface (the loop)...

a!localVariables(
  local!data: {
    { label: "Gears", detail: "Line-item details irrelevant for this problem repo", approval: null, comment: null},
    { label: "Switches", detail: "Other irrelevant details", approval: null, comment: null},
    { label: "Knobs", detail: "Other irrelevant details", approval: null, comment: null},
    { label: "Levers", detail: "Other irrelevant details", approval: null, comment: null},
  },
  {
    a!forEach(
      items:local!data,
      expression: rule!SH_FocusProblemChild(local!data[fv!index])
    )
  /*rule!SH_FocusProblemChild(local!data[1]),*/
  /*rule!SH_FocusProblemChild(local!data[2]),*/
  /*rule!SH_FocusProblemChild(local!data[3]),*/
  /*rule!SH_FocusProblemChild(local!data[4])*/
  }
)

Here is the "child" interface (that renders the controls)...  It takes one rule input of type Any Type.

{
  a!sectionLayout(
    label: ri!item.label,
    contents: {
      a!richTextDisplayField(
        label: "Review Data",
        labelPosition: "ADJACENT",
        value: a!richTextItem(text: ri!item.detail)
      )
    }
  ),
  a!sectionLayout(
    contents: {
      a!columnsLayout(
        columns: {
          a!columnLayout(
            contents: {
              a!dropdownField(
                label: "Approval",
                placeholder: "Select a value",
                choiceLabels: { "Approved", "Denied" },
                choiceValues: { "Approved", "Denied" },
                value: ri!item.approval,
                saveInto: ri!item.approval
              )
            }
          ),
          a!columnLayout(
            contents: {
              a!textField(
                label: "Comment",
                value: ri!item.comment,
                saveInto: ri!item.comment
                
              )
            },
            width: "3X"
          )
        }
      )
    }
  ),
  a!sectionLayout()
}

  Discussion posts and replies are publicly visible

Parents
  • 0
    Certified Lead Developer

    Followup question: do you need to have the looping section contained in its own interface to reproduce the issue here?  Because otherwise it's easier for other users here to test this by giving a single portable / pastable interface:

    a!localVariables(
      local!data: {
        { label: "Gears", detail: "Line-item details irrelevant for this problem repo", approval: null, comment: null},
        { label: "Switches", detail: "Other irrelevant details", approval: null, comment: null},
        { label: "Knobs", detail: "Other irrelevant details", approval: null, comment: null},
        { label: "Levers", detail: "Other irrelevant details", approval: null, comment: null},
      },
      
      {
        a!forEach(
          items:local!data,
          expression: {
            a!sectionLayout(
              label: fv!item.label,
              contents: {
                a!richTextDisplayField(
                  label: "Review Data",
                  labelPosition: "ADJACENT",
                  value: a!richTextItem(text: fv!item.detail)
                )
              }
            ),
            a!sectionLayout(
              contents: {
                a!columnsLayout(
                  columns: {
                    a!columnLayout(
                      contents: {
                        a!dropdownField(
                          label: "Approval",
                          placeholder: "Select a value",
                          choiceLabels: { "Approved", "Denied" },
                          choiceValues: { "Approved", "Denied" },
                          value: fv!item.approval,
                          saveInto: fv!item.approval
                        )
                      }
                    ),
                    a!columnLayout(
                      contents: {
                        a!textField(
                          label: "Comment",
                          value: fv!item.comment,
                          saveInto: fv!item.comment
                        )
                      },
                      width: "3X"
                    )
                  }
                )
              }
            ),
            a!sectionLayout()
          }
        )
      }
    )

    I'll add, I've seen a similar issue to what you describe in one of my interfaces, where I have a text entry box to allow the user to "live filter" data that's being queried into a paging grid - sometimes (and not 100% predictably) the control will be lost mid-typing and I as the user need to re-focus the text box to continue typing.  But I've never really had the time or attention span to do a deep-dive troubleshoot.

  • The separate interface was merely because that is how it fits into the larger application I am building.  For purposes of this question, the separate interface is likely irrelevant.

    But, it does make it easier to "unroll" the loop for illustrative purposes since then you only have to call the child interface 4 times (as shown above).  It would be much messier to unroll this on a single interface.

Reply
  • The separate interface was merely because that is how it fits into the larger application I am building.  For purposes of this question, the separate interface is likely irrelevant.

    But, it does make it easier to "unroll" the loop for illustrative purposes since then you only have to call the child interface 4 times (as shown above).  It would be much messier to unroll this on a single interface.

Children