I'm new to Appian. I have a user main page, and the user is able to click on a icon within the read-only grid, which is a recordactionlink, launching the interface to carry out managing of user information. Now, it would be simple if it was just the user I am handling.
Considering that this action is within the "Users" Record Type as a related action, I was planning to also use this same interface to do management of another record type "Access" within the same interface. My issue is with the Access of course.
With it being a grid/gridcolumn layout, with 3 columns, Location/Department/Role, the user is only able to populate the Access Record Type, 1 row per Location. Basically, the User Record Type and the Access Record Type has a one-to-many relationship. In an attempt to control the amount of rows the user is allowed to create within this interface, I first used a!for each to loop through the location Record Type, which basically ensures there's only as many rows as there is locations.
And within each row, I have Department/Role, which both firstly loops through the Access Record Type, filtering based on the fields of UserID (saved when selecting from the main page), and LocationID (contained in a local variable within each iteration. This helped me dynamically display data that already exists within the Access Record Type, displaying null for fields that don't exist.
Here is the main issue. How do I get the ever-changing (due to both Department and Role being dropdowns accessible at all times) data from each iteration to be saved into a singular rule input, which I will be trying to send into the Access Record Type as separate rows, through a process model?
Discussion posts and replies are publicly visible
yongj783799 said:data from each iteration to be saved into a singular rule input
Not sure how that would work? A singular rule input can only take one value.
This is a great explanation of your overall use case, but I do not understand where the issue comes up. Can you help me with this. Also, can you share and code or screenshots?
Hello Stefan! Thank you for replying to my Thread. Here, let me share some screenshots and code.
Before clicking into the interface
In the interface
Relevant Record Types
Code Involving the Interface
a!localVariables( local!aggregatedAccess: {}, local!departments: a!queryRecordType( recordType: 'IM2 Department', pagingInfo: a!pagingInfo( startIndex: 1, batchSize: 10 ), fields: { 'Department', 'DepartmentID' } ).data, a!headerContentLayout( isHeaderFixed: true, contents: { a!columnsLayout( columns: { a!columnLayout( showWhen: a!isPageWidth( { "DESKTOP_WIDE", "DESKTOP", "DESKTOP_NARROW", "TABLET_LANDSCAPE" } ) ), a!columnLayout( contents: { a!sectionLayout( label: "Details", labelSize: "MEDIUM", labelColor: "STANDARD", contents: { a!cardLayout( contents: { a!columnsLayout( columns: { a!columnLayout( contents: { a!textField( label: "Name", labelPosition: "ABOVE", value: ri!record['UserName'], saveInto: { ri!record['UserName'], ri!user['UserName'] }, characterLimit: 255, showCharacterCount: false, required: true, marginAbove: "LESS" ), a!textField( label: "Email", labelPosition: "ABOVE", value: ri!record['Email'], saveInto: { ri!record['Email'], ri!user['Email'] }, characterLimit: 255, showCharacterCount: false, required: true, marginAbove: "LESS" ), a!dropdownField( data: 'IM2 Care Home', choiceLabels: 'CareHome', choiceValues: 'CareHomeID', label: "Default Care Home", labelPosition: "ABOVE", placeholder: "Select a care home", value: ri!record['DefaultCareHome'], saveInto: { ri!record['DefaultCareHome'], ri!user['DefaultCareHome'] }, searchDisplay: "AUTO", required: true ), a!checkboxField( choiceLabels: { "Is Active" }, choiceValues: { true }, labelPosition: "COLLAPSED", value: if( ri!record['IsActive'], true, null ), saveInto: { a!save( ri!record['IsActive'], if(isnull(save!value), false, true) ), ri!user['IsActive'] }, spacing: "MORE", marginAbove: "STANDARD" ), a!sectionLayout( label: "Interactions", labelIcon: "address-book", labelColor: "NEGATIVE", contents: { a!sideBySideLayout( items: { a!sideBySideItem( item: a!textField( label: "Created On", value: if( a!isNotNullOrEmpty(ri!record['CreatedOn']), ri!record['CreatedOn'], "-" ), readOnly: true ) ), a!sideBySideItem( item: a!textField( label: "Created By", value: if( a!isNotNullOrEmpty(ri!record['CreatedBy']), ri!record['CreatedBy'], "-" ), readOnly: true ) ) } ), a!sideBySideLayout( items: { a!sideBySideItem( item: a!textField( label: "Modified On", value: if( a!isNotNullOrEmpty(ri!record['ModifiedOn']), ri!record['ModifiedOn'], "-" ), readOnly: true ) ), a!sideBySideItem( item: a!textField( label: "Modified By", value: if( a!isNotNullOrEmpty(ri!record['ModifiedBy']), ri!record['ModifiedBy'], "-" ), readOnly: true ) ) } ) }, isCollapsible: true, isInitiallyCollapsed: true, marginAbove: "STANDARD" ) }, width: "" ) }, alignVertical: "TOP" ) }, style: "NONE", shape: "SEMI_ROUNDED", padding: "MORE" ) }, marginAbove: "MORE" ), ----------- RELEVANT SECTION ----------- a!sectionLayout( label: "Access", labelSize: "MEDIUM", labelColor: "STANDARD", contents: { a!cardLayout( contents: { a!gridLayout( headerCells: { a!gridLayoutHeaderCell(label: "Care Home"), a!gridLayoutHeaderCell(label: "Department"), a!gridLayoutHeaderCell(label: "Debugging AccessID"), a!gridLayoutHeaderCell(label: "User Role") }, rows: a!forEach( items: a!queryRecordType( recordType: 'IM2 Care Home', pagingInfo: a!pagingInfo(startIndex: 1, batchSize: 10) ).data, expression: a!localVariables( /*variables are set here so that each row can have their own*/ local!careHome: fv!item['CareHome'], local!careHomeID: fv!item['CareHomeID'], /*ensuring that the access records retrieved match by UserID + CarehomeID*/ local!access: a!queryRecordType( recordType: 'recordType!{e1ec6c3c-c288-4497-a5bc-968693c49dbb}IM2 Access', fields: { 'UserID', 'DepartmentID', 'UserRoleID', 'CareHomeID' }, filters: a!queryLogicalExpression( operator: "AND", filters: { /*querying access table by matching Access Carehome ID with looped Carehome ID*/ a!queryFilter( field: 'CareHomeID', operator: "=", value: local!careHomeID ), /*querying access table by matching Acess user ID with selected user ID*/ a!queryFilter( field: 'UserID', operator: "=", value: if( a!isNullOrEmpty(ri!record['UserID']), 1, ri!record['UserID'] ) ) } ), pagingInfo: a!pagingInfo( startIndex: 1, batchSize: 1 ) ).data, /*handling department if record exist, also converting to Integer for querying*/ local!selectedDepartment: if( a!isNullOrEmpty(local!access), null, index( a!forEach( items: local!access, expression: tointeger(fv!item['DepartmentID']) ), 1, null ) ), /*handling default values before validating it within dropdown*/ local!selectedUserRole: if( a!isNullOrEmpty(local!access), null, index( a!forEach( items: local!access, expression: tointeger(fv!item['UserRoleID']) ), 1, null ) ), /*To filter out the selected department to see has what roles linked*/ local!filteredRoles: if( a!isNullOrEmpty(local!selectedDepartment), null, a!queryRecordType( recordType: 'IM2 DepartmentToUserRole', pagingInfo: a!pagingInfo( startIndex: 1, batchSize: 20 ), fields: 'UserRoleID', filters: a!queryFilter( field: 'DepartmentID', operator: "=", value: local!selectedDepartment ) ).data ), /*To take out all user role IDs based on the filter*/ local!userRoleIDs: if( a!isNullOrEmpty(local!filteredRoles), null, a!forEach( items: local!filteredRoles, expression: fv!item['UserRoleID'] ) ), /*to get the data to display in the user role dropdown*/ local!userRoleDropdown: if( a!isNullOrEmpty(local!userRoleIDs), null, a!queryRecordType( recordType: 'IM2 User Role', pagingInfo: a!pagingInfo(startIndex: 1, batchSize: 10), fields: { 'UserRole', 'UserRoleID' }, filters: a!queryFilter( field: 'UserRoleID', operator: "in", value: local!userRoleIDs ) ).data ), a!gridRowLayout( contents: { a!textField( label: "Care Home", value: local!careHome, readOnly: true ), a!dropdownField( choiceLabels: index(local!departments, 'Department', {}), choiceValues: index(local!departments, 'DepartmentID', {}), label:"Department", placeholder: "Select a department", value: local!selectedDepartment, saveInto: { local!selectedDepartment, a!save( target: local!selectedDepartment, value: if( a!isNullOrEmpty(save!value), null, save!value ) ), }, disabled: if( isnull(local!selectedUserRole), false, true ) ), a!textField( label: "Test1", value: local!access['AccessID'] ), a!dropdownField( choiceLabels: index(local!userRoleDropdown, 'UserRole', {}), choiceValues: index(local!userRoleDropdown, 'UserRoleID', {}), label:"User Role", placeholder: "Select a user role", value: local!selectedUserRole, saveInto: { local!selectedUserRole, a!save( target: local!selectedUserRole, value: if( a!isNullOrEmpty(save!value), null, save!value ) ), ri!access['UserRoleID'] }, disabled: if( isnull(local!selectedDepartment), true, false ) ) } ) ) ) ) } ) } ), a!buttonLayout( primaryButtons: { a!buttonWidget( label: "Save", saveInto: { /*updating the user record type*/ a!save( target: ri!record['ModifiedOn'], value: now() ), a!save( target: ri!record['ModifiedBy'], value: loggedInUser() ) }, submit: true, style: "SOLID", validate: true ) }, secondaryButtons: { a!buttonWidget( label: "Cancel", value: true, saveInto: ri!cancel, submit: true, style: "OUTLINE", validate: false ) } ) }, width: "WIDE_PLUS" ), a!columnLayout( showWhen: a!isPageWidth( { "DESKTOP_WIDE", "DESKTOP", "DESKTOP_NARROW", "TABLET_LANDSCAPE" } ) ) } ) }, backgroundColor: "#fbfbfb" ) )
Essentially, my grid involves using multiple record types, and I would just like to save each row of information into the Access Record Type, depending on whether there are already existing rows with the related UserID and CareHomeID.
Additionally, I was hoping that within this interface, specifically the grid showing the Access, I am able to update existing records, delete rows within Access should the user deselect both the Department and User Role, create rows within Access should there be no existing records.
To explain what exactly I have issues with:
How can I get data stored within each row of the grid, updating whenever the user changes the value (no duplicates), and how can I get it to be written into the Access Record Type? I was looking towards things such as CDT, Rule Inputs, Process Model, a!update(), a!save(), Data Store, searching resources online such as AppianCommunity, Youtube, Documentation, AI, but couldn't really seem to find a solution.
Edit: the data from the record types already dynamically display in the interface by querying the relevant record types using identifiers, I just have issues with how I should be writing to the record type.
I would appreciate any feedback you can provide, and any suggestions you might give.
Thanks again Stefan!
Have you tried generating the record actions and the related actions automatically from the actions tab and check if they are fulfilling your requirement?
In general, the idea of user input tasks or process start forms is, that you modify the data stored in rule inputs. On submit, your process takes care of persisting the data to record(s)/database.
I hope this example gets your started: docs.appian.com/.../recipe-track-adds-and-deletes-in-an-inline-editable-grid.html