User Picker isn't saving my selection

I added a User Picker to my Interface. 

I have defined "Selected Users" as ri!selectedUsers (which is an array of type User)

I have defined "Save Into" as ri!selectedUsers

When I select user, the selection is not saved in the component. I have seen some advice regarding a!save, and using load and local variables, but I am missing something and can't seem to find it explicitly explained in videos or the documentation.

Any suggestions?

Thanks,

Rob

  Discussion posts and replies are publicly visible

Parents
  • I have attached the code below...

    Important part:

    a!pickerFieldUsers(
    label: "First Officer",
    labelPosition: "ABOVE",
    maxselections: 1,
    groupfilter: cons!TA_ALL_USERS,
    value: ri!selectedUser,
    saveInto: ri!selectedUser,
    validations: {}
    )

    And the rule input looks like this (an array of User):

    The behaviour is that the UI lets me enter a User name, but when I select it, it flashes in the "First Officer" field then disappears.

    It is a little weird, but I am probably just missing something simple....

    ============================

    a!formLayout(
    label: "Flight",
    contents: {
    a!columnsLayout(
    columns: {
    a!columnLayout(
    contents: {
    a!dateField(
    label: "Date",
    labelPosition: if(
    ri!readOnly,
    "ADJACENT",
    "ABOVE"
    ),
    value: ri!flight.date,
    saveInto: ri!flight.date,
    readOnly: ri!readOnly
    ),
    a!textField(
    label: "Captain",
    labelPosition: if(
    ri!readOnly,
    "ADJACENT",
    "ABOVE"
    ),
    value: ri!flight.captain,
    saveInto: ri!flight.captain,
    readOnly: ri!readOnly,
    validations: if(
    len(
    ri!flight.captain
    ) > 255,
    "Value may not be longer than 255 characters. You have entered " & len(
    ri!flight.captain
    ) & " characters.",
    null
    )
    ),
    a!textField(
    label: "Special Instructions",
    labelPosition: if(
    ri!readOnly,
    "ADJACENT",
    "ABOVE"
    ),
    value: ri!flight.specialInstructions,
    saveInto: ri!flight.specialInstructions,
    readOnly: ri!readOnly,
    validations: if(
    len(
    ri!flight.specialInstructions
    ) > 255,
    "Value may not be longer than 255 characters. You have entered " & len(
    ri!flight.specialInstructions
    ) & " characters.",
    null
    )
    )
    }
    ),
    a!columnLayout(
    contents: {
    a!textField(
    label: "Customer",
    labelPosition: if(
    ri!readOnly,
    "ADJACENT",
    "ABOVE"
    ),
    value: ri!flight.customer,
    saveInto: ri!flight.customer,
    readOnly: ri!readOnly,
    validations: if(
    len(
    ri!flight.customer
    ) > 255,
    "Value may not be longer than 255 characters. You have entered " & len(
    ri!flight.customer
    ) & " characters.",
    null
    )
    ),
    a!pickerFieldUsers(
    label: "First Officer",
    labelPosition: "ABOVE",
    maxselections: 1,
    groupfilter: cons!TA_ALL_USERS,
    value: ri!selectedUser,
    saveInto: ri!selectedUser,
    validations: {}
    )
    }
    )
    }
    ),
    {
    a!localVariables(
    local!employees: {
    {id: 1, name: "Elizabeth Ward", dept: "Engineering", role: "Senior Engineer", team: "Front-End Components", pto: 15, startDate: today()-500},
    {id: 2, name: "Michael Johnson", dept: "Finance", role: "Payroll Manager", team: "Accounts Payable", pto: 2, startDate: today()-100},
    {id: 3, name: "John Smith", dept: "Engineering", role: "Quality Engineer", team: "User Acceptance Testing", pto: 5, startDate: today()-1000},
    {id: 4, name: "Diana Hellstrom", dept: "Engineering", role: "UX Designer", team: "User Experience", pto: 49, startDate: today()-1200},
    {id: 5, name: "Francois Morin", dept: "Sales", role: "Account Executive", team: "Commercial North America", pto: 15, startDate: today()-700},
    {id: 6, name: "Maya Kapoor", dept: "Sales", role: "Regional Director", team: "Front-End Components", pto: 15, startDate: today()-1400},
    {id: 7, name: "Anthony Wu", dept: "Human Resources", role: "Benefits Coordinator", team: "Accounts Payable", pto: 2, startDate: today()-300}
    },
    /* This variable is used to pass the full row of data on the selected item to the part of the interface showing the details of the selected item. */
    /* Here we are pre-selecting a row by indexing into the sample data; however, the data for the pre-selected row would typically be passed in as a *
    * rule input or generated with a query. */
    local!selectedEmployee: local!employees[4],
    {
    a!columnsLayout(
    columns: {
    a!columnLayout(
    contents: {
    a!sectionLayout(
    label: "Legs",
    contents: {
    a!gridField(
    /* Replace the dummy data with a query, rule, or function that returns a datasubset and uses fv!pagingInfo as the paging configuration. */
    data: todatasubset(
    local!employees,
    fv!pagingInfo
    ),
    columns: {
    a!gridColumn(
    label: "Name",
    value: fv!row.name
    ),
    a!gridColumn(
    label: "Department",
    value: fv!row.dept
    )
    },
    pageSize: 7,
    selectable: true,
    selectionStyle: "ROW_HIGHLIGHT",
    selectionValue: index(local!selectedEmployee, "id", {}),
    selectionSaveInto: {
    /* This save replaces the value of the previously selected item with that of the newly selected item, ensuring only one item can be selected at once.*/
    a!save(
    local!selectedEmployee,
    if(
    length(fv!selectedRows) > 0,
    fv!selectedRows[length(fv!selectedRows)],
    null
    )
    )
    },
    shadeAlternateRows: false,
    rowHeader: 1
    )
    }
    )
    }
    ),
    a!columnLayout(
    contents: {
    a!sectionLayout(
    label: "Leg Details",
    contents: {
    a!richTextDisplayField(
    value: a!richTextItem(
    text: "No employee selected.",
    color: "SECONDARY",
    size: "MEDIUM",
    style: "EMPHASIS"
    ),
    showWhen: isnull(local!selectedEmployee)
    ),
    a!columnsLayout(
    columns: {
    a!columnLayout(
    contents: {
    a!textField(
    label: "Name",
    value: local!selectedEmployee.name,
    readOnly: true
    ),
    a!textField(
    label: "Department",
    value: local!selectedEmployee.dept,
    readOnly: true
    )
    }
    ),
    a!columnLayout(
    contents: {
    a!textField(
    label: "Role",
    value: local!selectedEmployee.role,
    readOnly: true
    ),
    a!textField(
    label: "Start Date",
    value: text(local!selectedEmployee.startDate, "MMM dd, yyyy"),
    readOnly: true
    )
    }
    ),
    a!columnLayout(
    contents: {
    a!textField(
    label: "Team",
    value: local!selectedEmployee.team,
    readOnly: true
    ),
    a!textField(
    label: "Available PTO",
    value: local!selectedEmployee.pto & " days",
    readOnly: true
    )
    }
    )
    },
    showWhen: not(isnull(local!selectedEmployee))
    )
    }
    )
    }
    )
    }
    )
    }
    )
    }
    },
    buttons: a!buttonLayout(
    primaryButtons: {
    a!buttonWidget(
    label: "Submit",
    submit: true,
    style: "PRIMARY"
    )
    },
    secondaryButtons: {
    a!buttonWidget(
    label: "Cancel",
    value: true,
    saveInto: ri!cancel,
    submit: true,
    style: "NORMAL",
    validate: false
    )
    },
    showWhen: or(
    isnull(
    ri!readOnly
    ),
    not(
    ri!readOnly
    )
    )
    )
    )

  • 0
    Certified Lead Developer
    in reply to robertd0002

    As a preliminary piece of advice: when entering a comment, use the menu "Insert -> Code" to insert a Code box which will both retain your formatting as well as not making your comment 5 pages long.  You should be able to do this also if you edit an existing comment.  I'll take a glance at your code as soon as I can and see if I can spot anything. 

    Meanwhile it might help you to reduce the case to something absurdly simple and get that working at least - I banged out the following code in the last minute which works just fine for me:

    a!pickerFieldUsers(
      value: ri!selectedUsers,
      saveInto: ri!selectedUsers,
      maxSelections: 3
    )

    and the expected result, which works fine:

  • 0
    Certified Lead Developer
    in reply to robertd0002

    Shoot, I was actually about to ask you before whether it was only breaking in a process, but I forgot to.

    So, yes this is expected behavior when the Task setup is incomplete.  When saving a variable into a ri! variable in a SAIL form used on a task in a process, the rule input on the User Input Task node MUST map to an ACP (ac!) variable defined in that task.  You might think it would just save a "temporary" copy on the SAIL form without this, but it doesn't.  I'd be pretty surprised if this wasn't the root of your issue.

  • That makes sense. Thanks! I'll read up on the ac! variable and see if I can sort it out.

  • +1
    Certified Lead Developer
    in reply to robertd0002

    It's fairly straightforward luckily - basically you create an input variable on the user input task's Data tab matching the type you need (list of users in your case), then switch over to the "Forms" tab and find the rule input and set it to the newly-created ACP.

  • I tested it out this morning and it works perfectly. Thanks. 

  • One more quick question. I am pretty weak at writing expressions obviously. So, previously my Interface and CDT were all primitive types. The "user" field was just a text field for the "flight.firstofficer" field in the "flight CDT". NOW I am have a User Picker (that is stored in the parameter "selectedUser" - an array of type User), and I need to save it to the database.

    HOW would I take the parameter "selectedUser" and update the "flight.firstofficer" field? (so it can be stored into the database in the next step). 

    What sort of expression do I need to write to set the "flight.firstofficer" field?

    Is it something like ...

    {

    flight: flight.date=pv!date,... flight.firstofficer=ac!selectedUser[1].user.name,....

    }

    I understand my expression is probably ALL wrong, but you get the idea, I think I need to set the flight rule input to be a new "flight" CDT, and copy all the data over, and when it comes to the firstofficer field, grab the selectedUser.... 

    Can you point me to a video or document explaining how to write the expression correctly?

    Rob.

  • 0
    Certified Lead Developer
    in reply to robertd0002

    If I understand your question correctly, then the answer luckily is that it's a lot easier than you're making it.  You can have the user picker field store into a text field - when a user is cast as text, the resulting text value is just the username.  So for example, you could just point your user picker field at ri!flight.firstOfficer instead of using an intermediary field.

    Another approach would be to continue using the separate field, and then in a script task after the user input task, save the username value into the CDT property.  This adds steps but also potentially adds flexibility to do different things if needed.

  • That sounds great... I am really close to getting this working. One problem when I update the interface -- to do with arrays I believe.

    I've changed 

    "Save Selection To" to "ri!flight.firstOfficer"

    and

    "Selected Users" to ??? (I tried { touser(ri!flight.firstOfficer) } but that doesn't seem to work. I've tried "ri!flight.firstOfficer" but it has an issue with the type.

    Could not display interface. Please check definition and inputs. Interface Definition: Expression evaluation error at function a!pickerFieldUsers [line 83]: A user picker component [label=“First Officer”] has an invalid value for “value”. All users must be valid and visible to the viewer.

    Any suggestions?

  • 0
    Certified Lead Developer
    in reply to robertd0002

    is ri!flight an array or single?  is ".firstOfficer" an array within the CDT or single?

  • they are both single. The page manages one flight and it has one first officer(co pilot)

  • 0
    Certified Lead Developer
    in reply to robertd0002

    As far as I can tell, then, it should work for you to set both the value and the saveInto parameters to simply point to "ri!flight.firstOfficer".  Note that if some other data has become saved into it in the mean time, you might need to click "Test" again and reload a fresh copy of the interface and data to avoid errors.

Reply Children
No Data