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.

  • 0
    Certified Lead Developer
    in reply to stevenh6272

    Gotcha.  I should also add that my above code works for me but I can't get the issue to happen when I try - though if you have any specific steps to try, I'd be curious.

  • Interesting.... perhaps the child interface is critical to reproduce this.

  • +1
    Certified Lead Developer
    in reply to stevenh6272

    Also i'd be curious what would happen in your original example if you fix this incorrect line:

    expression: rule!SH_FocusProblemChild(local!data[fv!index])

    which, unless you have very special / unusual requirements, should actually be written as:

    expression: rule!SH_FocusProblemChild(fv!item)

  • Interesting.... changing to fv!item does prevent the focus from getting lost.

    However, I am intentionally referencing the source data directly.  Because of how this fits into the larger scenario.  The parent interface has a rule input that provides the data used to drive the interface.  This data needs to stay up-to-date as the user selects drop-down information and enters comments (because this is used to drive status icons).  

    I was having trouble when using fv!item and local variables where the changed data did not flow automatically back up to the parent form's rule input.  By referencing the rule input directly in the for loop, changes to the controls on the child form were immediately reflected in the parent form's rule input without having to do any a!save() stuff.

    I'm not sure if I can use fv!item.  I believe I already tried this a couple weeks ago but it did not work.  I could try again and see what happens.

  • Ok.  I changed to use fv!item and the problem with the focus is gone and my data is flowing correctly to the parent interface.  So, I must have been doing something wrong a couple weeks ago that drove me to reference the rule input directly within the foreach loop instead of using fv!item.  

    Thank you for your input.

  • 0
    Certified Lead Developer
    in reply to stevenh6272

    Cool, thanks for confirming - i might try doubling back to the interface I had that problem with and seeing if there's a similar issue with reference-by-index or something happening there.  Usually if/when I use that sort of approach, it's because there wasn't any other way - but in this case I simply don't remember what it might have been (even if anything similar).

Reply
  • 0
    Certified Lead Developer
    in reply to stevenh6272

    Cool, thanks for confirming - i might try doubling back to the interface I had that problem with and seeing if there's a similar issue with reference-by-index or something happening there.  Usually if/when I use that sort of approach, it's because there wasn't any other way - but in this case I simply don't remember what it might have been (even if anything similar).

Children
No Data