Hi All,
I'm a beginner of Appian, and I would like to know how to save a row order in a grid.
In a grid in an interface, I put a arrow for up and down to move rows.
I need to save the order, so the changed order should be saved and updated to DB.
I should create a column in DB to save a row order, but it does not work.
What I want to do is ... when I change the row order by clicking arrow icon and the order is changed, I would like to save the ordering information for next time. When a user open the window next time, a user requires to see the row which was changed by user clicking an arrow.
I need your help.....
Best regards,
Discussion posts and replies are publicly visible
a!localVariables( /* * local!employess is provided in this recipe as a way to start with hard-coded * data. However, this data is identical to the data created from the entity-backed * tutorial. Replace the hard-coded data with a query to the employee data store * entity and all of the employee records from the tutorial will appear. * * To replace this data with your own, replace (ctrl+H or cmd+H) all references to * local!employees with your data source, either via rule input or local variable. */ local!tempEmployHolder, local!employees: { a!map( id: 1, firstName: "John", lastName: "Smith", department: "Engineering", title: "Director", phoneNumber: "555-123-4567", startDate: today() - 360, sequence: 1 ), a!map( id: 2, firstName: "Michael", lastName: "Johnson", department: "Finance", title: "Analyst", phoneNumber: "555-987-6543", startDate: today() - 360, sequence: 2 ), a!map( id: 3, firstName: "Mary", lastName: "Reed", department: "Engineering", title: "Software Engineer", phoneNumber: "555-456-0123", startDate: today() - 240, sequence: 3 ), }, a!formLayout( label: "Example: Add,Update, or Remove Employee Data", contents: { a!gridLayout( totalCount: count(local!employees), headerCells: { a!gridLayoutHeaderCell(label: "First Name"), a!gridLayoutHeaderCell(label: "Last Name"), a!gridLayoutHeaderCell(label: "Department"), a!gridLayoutHeaderCell(label: "Title"), a!gridLayoutHeaderCell(label: "Phone Number"), a!gridLayoutHeaderCell(label: "Start Date", align: "RIGHT"), /* For the "Remove" column */ a!gridLayoutHeaderCell(label: ""), a!gridLayoutHeaderCell(label: "") }, /* Only needed when some columns need to be narrow */ columnConfigs: { a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 3), a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 3), a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 3), a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 3), a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 3), a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 2), a!gridLayoutColumnConfig(width: "ICON"), a!gridLayoutColumnConfig(width: "ICON") }, /* * a!forEach() will take local!employee data and used that data to loop through an * expression that creates each row. * * When modifying the recipe to work with your data, you only need to change: * 1.) the number of fields in each row * 2.) the types of fields for each column (i.e. a!textField() for text data elements) * 3.) the fv!item elements. For example fv!item.firstName would change to fv!item.yourdata */ rows: a!forEach( items: local!employees, expression: a!gridRowLayout( contents: { /* For the First Name Column*/ a!textField( /* Labels are not visible in grid cells but are necessary to meet accessibility requirements */ label: "first name " & fv!index, value: fv!item.firstName, saveInto: fv!item.firstName, required: true ), /* For the Last Name Column*/ a!textField( label: "last name " & fv!index, value: fv!item.lastName, saveInto: fv!item.lastName, required: true ), /* For the Department Column*/ a!dropdownField( label: "department " & fv!index, placeholder: "-- Select -- ", choiceLabels: { "Corporate", "Engineering", "Finance", "Human Resources", "Professional Services", "Sales" }, choiceValues: { "Corporate", "Engineering", "Finance", "Human Resources", "Professional Services", "Sales" }, value: fv!item.department, saveInto: fv!item.department, required: true ), /* For the Title Column*/ a!textField( label: "title " & fv!index, value: fv!item.title, saveInto: fv!item.title, required: true ), /* For the Phone Number Column*/ a!textField( label: "phone number " & fv!index, placeholder: "555-456-7890", value: fv!item.phoneNumber, saveInto: fv!item.phoneNumber ), /* For the Start Date Column*/ a!dateField( label: "start date " & fv!index, value: fv!item.startDate, saveInto: fv!item.startDate, required: true, align: "RIGHT" ), /* For the Moving Column Up*/ a!richTextDisplayField( value: a!richTextIcon( icon: "arrow-circle-o-up", altText: "Move " & fv!index, caption: "Move " & fv!item.firstName & " " & fv!item.lastName, link: a!dynamicLink( value: fv!index, saveInto: { local!employees[fv!index - 1].sequence, a!save( local!employees[fv!index].sequence, fv!index - 1 ), a!save( local!tempEmployHolder, index(local!employees, fv!index - 1, null()) ), a!save( local!employees, a!update( local!employees, fv!index - 1, index(local!employees, fv!index, null()) ) ), a!save( local!employees, a!update( local!employees, fv!index, local!tempEmployHolder ) ), a!save(local!tempEmployHolder, null()) } ), linkStyle: "STANDALONE", color: "NEGATIVE", showWhen: not(fv!isFirst) ) ), a!richTextDisplayField( value: a!richTextIcon( icon: "arrow-circle-down", altText: "Move " & fv!index, caption: "Move " & fv!item.firstName & " " & fv!item.lastName, link: a!dynamicLink( value: fv!index, saveInto: { local!employees[fv!index + 1].sequence, a!save( local!employees[fv!index].sequence, fv!index + 1 ), a!save( local!tempEmployHolder, index(local!employees, fv!index + 1, null()) ), a!save( local!employees, a!update( local!employees, fv!index + 1, index(local!employees, fv!index, null()) ) ), a!save( local!employees, a!update( local!employees, fv!index, local!tempEmployHolder ) ), a!save(local!tempEmployHolder, null()) } ), linkStyle: "STANDALONE", color: "NEGATIVE", showWhen: not(fv!isLast) ) ) }, id: fv!index ) ), addRowlink: a!dynamicLink( label: "Add Employee", /* * For your use case, set the value to a blank instance of your CDT using * the type constructor, e.g. type!Employee(). Only specify the field * if you want to give it a default value e.g. startDate: today()+1. */ value: { startDate: today() + 1 }, saveInto: { a!save( local!employees, append(local!employees, save!value) ) } ), rowHeader: 1 ) }, buttons: a!buttonLayout( primaryButtons: a!buttonWidget(label: "Submit", submit: true) ) ) )
saitoy6477 said:I should create a column in DB to save a row order, but it does not work.
What exactly "does not work"?
In short my typical design is like this:
- "sort" field in DB
- up/down swaps the items in the underlying data
- then iterates on the list to renumber the sort value all items
- then write the data back to the DB
To get started, a good standalone example is this: https://docs.appian.com/suite/help/24.3/recipe-add-edit-and-remove-data-in-an-inline-editable-grid.html
saitoy6477 You can use a Id with the above map data . Id will uniquely identify each record same as like Db primary key . You can use below code i just tried for down functionality you can use same for Up as well .
a!localVariables( local!items: { { id: 1, item: "Item 1", qty: 1, unitPrice: 10 }, { id: 2, item: "Item 2", qty: 2, unitPrice: 20 } }, a!gridLayout( label: "Products", instructions: "Update the item name, quantity, or unit price.", headerCells: { a!gridLayoutHeaderCell(label: "Item"), a!gridLayoutHeaderCell(label: "Qty"), a!gridLayoutHeaderCell(label: "Unit Price"), a!gridLayoutHeaderCell(label: "Total", align: "RIGHT"), a!gridLayoutHeaderCell(label: " "), }, rows: a!forEach( items: local!items, expression: a!gridRowLayout( contents: { a!textField( value: fv!item.item, saveInto: fv!item.item ), a!integerField(value: fv!item.qty, saveInto: fv!item.qty), a!floatingPointField( value: fv!item.unitPrice, saveInto: fv!item.unitPrice ), a!textField( value: a!currency( isoCode: "USD", value: tointeger(fv!item.qty) * todecimal(fv!item.unitPrice) ), readOnly: true, align: "RIGHT" ), a!richTextDisplayField( value: { a!richTextIcon( icon: "arrow-circle-down", showWhen: not(fv!isLast), link: a!dynamicLink( saveInto: { a!save( local!items, a!update( local!items, {fv!index,fv!index+1}, {index(local!items,(fv!index+1),null()),fv!item} ) ) } ) ), a!richTextIcon(icon: "arrow-circle-up") } ) } ) ), rowHeader: 1 ) )
thank you! I will try!
Thank you! I will try.
Makes code more readable.
Sure
A simple approach to swap items in a list is this:
a!update( ri!list, {ri!index1, ri!index2}, {ri!list[ri!index2], ri!list[ri!index1]} )
I created a utility expression that includes some range and null checks.
Thanks Stefan Helzle ,
will change the code and would also add some comments as well
is it possible to break page for the grid? gridField seems to have a "break page " as "page size", but editable grid "gridlayout" does not seem to have the "break page".