Editable grid

Hi All, 

I m a beginner in appian. As part of my request, I need to build a editable grid with record data rule input. I have 5 fields totally and I need to display them. Can someone help me how to configure edit button and add button and what actions I need to perform to save or update the values to the rule input. And i should add only one row at a time and all the fields in grid are mandatory. Can someone help me with the code. 

  Discussion posts and replies are publicly visible

  • 0
    Certified Lead Developer

    There are various recipes in the official documentation: https://docs.appian.com/suite/help/25.1/Editable_Grid_Component.html#record-type-example

    Have you tried anything already and/or having any particular trouble?

  •   I have tried this. I m able to get the data populated in the grid. But I m stuck at how to configure the add , edit and save buttons

  • Everytime when i edit add new row gets added into database. The above receipe i m not able to find configuring edit

  • 0
    Certified Senior Developer

    Hi  ,

    I guess this code might help you for editable grid ( add, remove ,edit )

    a!localVariables(
      local!data: {
        {
          empId: 1,
          firstName: "Test",
          lastName: "User 1",
          designation: "Consultant",
          department: "Delivery"
        },
        {
          empId: 2,
          firstName: "Test",
          lastName: "User 2",
          designation: "Junior Consultant",
          department: "Delivery"
        }
      },
      {
        a!gridLayout(
          label: "Editable Grid",
          labelPosition: "ABOVE",
          headerCells: {
            a!gridLayoutHeaderCell(label: "EMP ID"),
            a!gridLayoutHeaderCell(label: "FIRST NAME"),
            a!gridLayoutHeaderCell(label: "LAST NAME"),
            a!gridLayoutHeaderCell(label: "DESIGNATION"),
            a!gridLayoutHeaderCell(label: "DEPARTMENT"),
            a!gridLayoutHeaderCell(label: "ACTION"),
            
          },
          columnConfigs: {},
          rows: {
            a!forEach(
              items: local!data,
              expression: a!gridRowLayout(
                contents: {
                  a!integerField(
                    value: fv!item.empId,
                    saveInto: fv!item.empId
                  ),
                  a!textField(
                    value: fv!item.firstName,
                    saveInto: fv!item.firstName
                  ),
                  a!textField(
                    value: fv!item.lastName,
                    saveInto: fv!item.lastName
                  ),
                  a!textField(
                    value: fv!item.designation,
                    saveInto: fv!item.designation
                  ),
                  a!textField(
                    value: fv!item.department,
                    saveInto: fv!item.deparment
                  ),
                  a!richTextDisplayField(
                    value: {
                      a!richTextIcon(
                        icon: "times",
                        color: "NEGATIVE",
                        link: a!dynamicLink(
                          saveInto: a!save(local!data, remove(local!data, fv!index))
                        ),
                        linkStyle: "STANDALONE"
                      )
                    }
                  )
                }
              )
            )
          },
          totalCount: length(local!data),
          addRowLink: a!dynamicLink(
            label: "Add Emp",
            saveInto: a!save(
              local!data,
              append(
                local!data,
                {
                  empId: null,
                  firstName: null,
                  lastName: null,
                  deisgnation: null,
                  department: null
                }
              )
            )
          ),
          selectionSaveInto: {},
          validations: {},
          shadeAlternateRows: true
        )
      }
    )

  • 0
    Certified Lead Developer
    in reply to reenab0003

    Ensure that when you are editing, the primary key id column value is not overwritten. If originally id was 2 then after edit operation and submits also the id for that row still be 2. If it goes null somewhere then you will find a new row in database instead of the original row being updated. So look out for the 'id' column value in your interface and process. 

  • 0
    Certified Lead Developer
    in reply to reenab0003
    Everytime when i edit add new row gets added into database

    Without seeing the code you're attempting to use, it's hard to guess at a fix, fwiw.

  • 0
    Certified Senior Developer

    Hi  ,

     This code might help you for editable grid ( add, remove ,edit )

    a!localVariables(
      local!data: {
        a!map(
          studentId: 1,
          loginId: 1,
          lastName: "gill",
          phone: "9899878788",
          photoDocId: 168045,
          statusId: 11,
          modifiedOn: fn!datetime(2023, 12, 6, 10, 24, 45, 0),
          isActive: false,
          age: 23,
          createdBy: "Yashwanth",
          modifiedBy: "yashwanth.akula@yexle.com",
          emailAddress: "subman@gmail.com",
          firstName: "Subman",
          dob: fn!date(2000, 9, 29),
          createdOn: fn!datetime(2023, 12, 6, 5, 37, 29, 0)
        ),
        a!map(
          studentId: 2,
          loginId: 4,
          lastName: "PPP",
          phone: "9877776767",
          photoDocId: 168123,
          statusId: 12,
          modifiedOn: fn!datetime(2023, 12, 7, 6, 10, 24, 0),
          isActive: false,
          age: 33,
          createdBy: "Stark",
          modifiedBy: "Stark",
          emailAddress: "rahane@gmail.com",
          firstName: "RRR",
          dob: fn!date(1990, 11, 1),
          createdOn: fn!datetime(2023, 12, 7, 6, 9, 31, 0)
        ),
        a!map(
          studentId: 3,
          loginId: 5,
          lastName: "jaganadh",
          phone: "9855677665",
          photoDocId: 168181,
          statusId: 12,
          modifiedOn: fn!datetime(2023, 12, 8, 5, 9, 30, 0),
          isActive: false,
          age: 23,
          createdBy: "Mahesh",
          modifiedBy: "Mahesh",
          emailAddress: "puri@gmail.com",
          firstName: "puri",
          dob: fn!date(2000, 12, 8),
          createdOn: fn!datetime(2023, 12, 8, 4, 22, 40, 0)
        ),
        a!map(
          studentId: 5,
          loginId: 5,
          lastName: "jaganadh",
          phone: "9855677665",
          photoDocId: 168190,
          statusId: 10,
          modifiedOn: fn!datetime(2023, 12, 8, 5, 10, 4, 0),
          isActive: true,
          age: 23,
          createdBy: "Mahesh",
          modifiedBy: "yashwanth.akula@yexle.com",
          emailAddress: "puri@gmail.com",
          firstName: "puri",
          dob: fn!date(2000, 12, 8),
          createdOn: fn!datetime(2023, 12, 8, 4, 46, 15, 0)
        ),
        a!map(
          studentId: 6,
          loginId: 5,
          lastName: "KO",
          phone: "7877676556",
          photoDocId: 168234,
          statusId: 10,
          modifiedOn: fn!datetime(2023, 12, 8, 10, 2, 1, 0),
          isActive: true,
          age: 23,
          createdBy: "Mahesh",
          modifiedBy: "yashwanth.akula@yexle.com",
          emailAddress: "subman@gmail.com",
          firstName: "Yashwanth",
          dob: fn!date(2000, 10, 30),
          createdOn: fn!datetime(2023, 12, 8, 9, 49, 58, 0)
        ),
        a!map(
          studentId: 8,
          loginId: 4,
          lastName: "mahesh",
          phone: "7899875467",
          photoDocId: 168758,
          statusId: 10,
          modifiedOn: fn!datetime(2023, 12, 23, 12, 21, 44, 0),
          isActive: true,
          age: 23,
          createdBy: "Stark",
          modifiedBy: "yashwanth.akula@yexle.com",
          emailAddress: "pandu@gmail.com",
          firstName: "Pandu",
          dob: fn!date(2000, 12, 14),
          createdOn: fn!datetime(2023, 12, 23, 11, 59, 45, 0)
        ),
        a!map(
          studentId: 9,
          loginId: 4,
          lastName: "james",
          phone: "7899875467",
          photoDocId: 168761,
          statusId: 11,
          modifiedOn: fn!datetime(2023, 12, 23, 12, 21, 52, 0),
          isActive: true,
          age: 23,
          createdBy: "Stark",
          modifiedBy: "yashwanth.akula@yexle.com",
          emailAddress: "pandu@gmail.com",
          firstName: "Ferguson",
          dob: fn!date(2000, 12, 14),
          createdOn: fn!datetime(2023, 12, 23, 12, 18, 33, 0)
        ),
        a!map(
          studentId: 10,
          loginId: 3,
          lastName: "james",
          phone: "7899875467",
          photoDocId: 169025,
          statusId: 11,
          modifiedOn: fn!datetime(2024, 1, 3, 14, 47, 51, 0),
          isActive: true,
          age: 24,
          createdBy: "Taylor",
          modifiedBy: "yashwanth.akula@yexle.com",
          emailAddress: "pandu@gmail.com",
          firstName: "Ferguson",
          dob: fn!date(2000, 12, 14),
          createdOn: fn!datetime(2024, 1, 3, 14, 37, 42, 0)
        ),
        a!map(
          studentId: 12,
          loginId: 1,
          lastName: "mouse",
          phone: "5545456767",
          photoDocId: 170248,
          statusId: 11,
          modifiedOn: fn!datetime(2024, 8, 27, 5, 48, 52, 0),
          isActive: true,
          age: 22,
          createdBy: "Yashwanth",
          modifiedBy: "yashwanth.akula@yexle.com",
          emailAddress: "mickey@gmail.com",
          firstName: "mickey",
          dob: fn!date(2002, 10, 31),
          createdOn: fn!datetime(2024, 1, 21, 8, 55, 54, 0)
        )
      },
      local!readOnly: { 0 },
      {
        a!gridLayout(
          label: "Students",
          labelPosition: "ABOVE",
          headerCells: {
            a!gridLayoutHeaderCell(label: "Name"),
            a!gridLayoutHeaderCell(label: "age"),
            a!gridLayoutHeaderCell(label: "phone"),
            a!gridLayoutHeaderCell(label: "Email"),
            a!gridLayoutHeaderCell(label: "DOB"),
            a!gridLayoutHeaderCell(label: ""),
            a!gridLayoutHeaderCell(label: "")
          },
          columnConfigs: {
            a!gridLayoutColumnConfig(),
            a!gridLayoutColumnConfig(),
            a!gridLayoutColumnConfig(),
            a!gridLayoutColumnConfig(),
            a!gridLayoutColumnConfig(),
            a!gridLayoutColumnConfig(width: "ICON"),
            a!gridLayoutColumnConfig(width: "ICON")
          },
          rows: {
            a!forEach(
              items: local!data,
              expression: a!gridRowLayout(
                contents: {
                  a!textField(
                    value: fv!item.lastName,
                    saveInto: fv!item.lastName,
                    readOnly: and(
                      not(contains(local!readOnly, fv!index)),
                      a!isNotNullOrEmpty(fv!item.lastName)
                    )
                  ),
                  a!integerField(
                    value: fv!item.age,
                    saveInto: fv!item.age,
                    readOnly: and(
                      not(contains(local!readOnly, fv!index)),
                      a!isNotNullOrEmpty(fv!item.age)
                    )
                  ),
                  a!textField(
                    value: fv!item.phone,
                    saveInto: fv!item.phone,
                    readOnly: and(
                      not(contains(local!readOnly, fv!index)),
                      a!isNotNullOrEmpty(fv!item.phone)
                    )
                  ),
                  a!textField(
                    value: fv!item.emailAddress,
                    saveInto: fv!item.emailAddress,
                    readOnly: and(
                      not(contains(local!readOnly, fv!index)),
                      a!isNotNullOrEmpty(fv!item.emailAddress)
                    )
                  ),
                  a!dateField(
                    value: fv!item.dob,
                    saveInto: fv!item.dob,
                    readOnly: and(
                      not(contains(local!readOnly, fv!index)),
                      a!isNotNullOrEmpty(fv!item.dob)
                    )
                  ),
                  a!richTextDisplayField(
                    value: if(
                      and(
                        not(contains(local!readOnly, fv!index)),
                        a!isNotNullOrEmpty(fv!item.studentId)
                      ),
                      a!richTextIcon(
                        icon: "pencil",
                        caption: "Edit Record",
                        linkStyle: "STANDALONE",
                        link: a!dynamicLink(
                          saveInto: {
                            a!save(
                              local!readOnly,
                              append(local!readOnly, fv!index)
                            )
                          }
                        )
                      ),
                      a!richTextIcon(
                        icon: "floppy-o",
                        color: "POSITIVE",
                        caption: "Save record",
                        linkStyle: "STANDALONE",
                        link: a!dynamicLink(
                          saveInto: {
                            if(
                              a!isNullOrEmpty(fv!item.studentId),
                              {},
                              a!save(
                                local!readOnly,
                                remove(
                                  local!readOnly,
                                  wherecontains(fv!index, local!readOnly)
                                )
                              )
                            )
                          }
                        )
                      )
                    )
                  ),
                  a!richTextDisplayField(
                    value: {
                      a!richTextIcon(
                        icon: "times",
                        color: "NEGATIVE",
                        linkStyle: "STANDALONE",
                        caption: "remove row",
                        link: a!dynamicLink(
                          saveInto: a!save(local!data, remove(local!data, fv!index))
                        ),
                        showWhen: a!isNullOrEmpty(fv!item)
                      ),
                      a!richTextIcon(
                        icon: "trash",
                        color: "NEGATIVE",
                        linkStyle: "STANDALONE",
                        caption: "delete ",
                        link: a!dynamicLink(saveInto: {}),
                        showWhen: a!isNotNullOrEmpty(fv!item.studentId)
                      )
                    }
                  )
                }
              )
            )
          },
          addRowLink: a!dynamicLink(
            label: "Add",
            saveInto: {
              a!save(
                local!data,
                append(local!data, save!value)
              )
            }
          ),
          selectionSaveInto: {},
          validations: {},
          shadeAlternateRows: true
        )
      }
    )

  • a!localVariables(
      local!sectionValue: index(
        ri!sectionDetails,
        'recordType!{9d43eebd-bb55-4fcd-ac73-cce13c477378}TTPK_r_pstConfiguration.fields.{4699341c-986d-4876-808e-d8db1ab0484d}sectionValue',
        null()
      ),
      local!originalParseJson: if(
        a!isNullOrEmpty(local!sectionValue),
        null(),
        a!forEach(
          items: local!sectionValue,
          expression: a!fromJson(fv!item)
        )
      ),
      local!editingRowIndex,
      local!parseJson: local!originalParseJson,
      local!dataToWrite: a!forEach(
        items: ri!sectionDetails,
        expression: cast(
          'recordType!{9d43eebd-bb55-4fcd-ac73-cce13c477378}TTPK_r_pstConfiguration',
          fv!item
        )
      ),
      local!extractKey: a!keys(index(local!parseJson, 1, null())),
      local!headers: a!forEach(
        local!extractKey,
        displayvalue(
          fv!item,
          cons!TTPK_TXT_JSON_PARAMETERS,
          cons!TTPK_TXT_COLUMN_LABELS,
          null()
        )
      ),
      local!isLogisticsLevelCollapse: false(),
      local!isEditable: false,
      local!isNewRow: false,
      local!disableCancel: true,
      local!disableSave: true,
      {
        a!sideBySideLayout(
          items: {
            a!sideBySideItem(
              item: a!richTextDisplayField(
                labelPosition: "COLLAPSED",
                value: {
                  a!richTextItem(
                    text: {
                      'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{2fab036a-523a-424c-96a0-2e73bb424007}Logistics Impact Levels'
                    },
                    size: "STANDARD",
                    style: "STRONG"
                  )
                },
                marginAbove: "STANDARD"
              )
            ),
            a!sideBySideItem(
              item: a!richTextDisplayField(
                value: a!richTextIcon(
                  icon: if(
                    local!isLogisticsLevelCollapse,
                    "caret-down",
                    "caret-up"
                  ),
                  link: a!dynamicLink(
                    saveInto: {
                      a!save(
                        local!isLogisticsLevelCollapse,
                        not(local!isLogisticsLevelCollapse)
                      )
                    }
                  ),
                  linkStyle: "STANDALONE",
                  color: "#008294",
                  size: "MEDIUM"
                ),
                align: "RIGHT"
              )
            )
          }
        ),
        a!horizontalLine(marginAbove: "NONE", marginBelow: "LESS"),
        a!cardLayout(
          contents: {
            a!gridLayout(
              label: "",
              labelPosition: "ABOVE",
              headerCells: {
                a!gridLayoutHeaderCell(
                  label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{04c61647-fadb-43ec-876c-119024f26a05}Logistics Impact'
                ),
                a!gridLayoutHeaderCell(
                  label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{82d09d08-4553-49ea-82ee-85ea089c9298}Operator'
                ),
                a!gridLayoutHeaderCell(
                  label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{a3643f4a-801c-4e26-b824-e347f80959dd}Previous From'
                ),
                a!gridLayoutHeaderCell(
                  label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{9978e4b7-d23e-4d2d-b460-6ce00b7332f9}Previous To'
                ),
                a!gridLayoutHeaderCell(
                  label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{abbf3ef4-fa23-4e52-9e95-ee0708a58a68}From'
                ),
                a!gridLayoutHeaderCell(
                  label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{d932cdec-954d-4707-8950-9bda619fcc4c}To'
                ),
                a!gridLayoutHeaderCell(label: ""),
                
              },
              columnConfigs: {},
              rows: {
                a!forEach(
                  items: local!parseJson,
                  expression: a!localVariables(
                    a!gridRowLayout(
                      id: fv!index,
                      contents: {
                        a!textField(
                          label: "logisticImpact" & fv!index,
                          value: fv!item.logisticImpact,
                          saveInto: fv!item.logisticImpact,
                          readOnly: true()
                        ),
                        a!textField(
                          /* Labels are not visible in grid cells but are necessary to meet accessibility requirements */
                          label: "operator" & fv!index,
                          value: fv!item.operator,
                          saveInto: fv!item.operator,
                          readOnly: true()
                        ),
                        /* For the Title Column*/
                        a!textField(
                          label: "fromPreviousValue" & fv!index,
                          value: fv!item.fromPreviousValue,
                          saveInto: fv!item.fromPreviousValue,
                          readOnly: true()
                        ),
                        /* For the Phone Number Column*/
                        a!textField(
                          label: "toPreviousValue" & fv!index,
                          value: fv!item.toPreviousValue,
                          saveInto: fv!item.toPreviousValue,
                          readOnly: true()
                        ),
                        a!textField(
                          label: "from" & fv!index,
                          value: fv!item.from,
                          saveInto: fv!item.from,
                          readOnly: if(
                            a!isNullOrEmpty(local!editingRowIndex),
                            true,
                            if(
                              local!editingRowIndex = fv!index,
                              false,
                              true
                            )
                          )
                        ),
                        a!textField(
                          label: "to" & fv!index,
                          value: fv!item.to,
                          saveInto: fv!item.to,
                          disabled: not(
                            if(
                              fv!item.logisticImpact = "High",
                              true,
                              false
                            )
                          ),
                          readOnly: if(
                            a!isNullOrEmpty(local!editingRowIndex),
                            true,
                            if(
                              local!editingRowIndex = fv!index,
                              false,
                              true
                            )
                          )
                        ),
                        a!richTextDisplayField(
                          value: a!richTextIcon(
                            icon: "pencil",
                            linkStyle: "STANDALONE",
                            caption: "Click here to edit",
                            link: a!dynamicLink(
                              saveInto: {
                                a!save(local!editingRowIndex, fv!index),
                                a!save(local!disableCancel, false),
                                a!save(local!disableSave, false)
                              }
                            )
                          )
                        )
                      }
                    )
                  )
                )
              },
              selectionSaveInto: {},
              validations: {},
              shadeAlternateRows: true
            ),
            a!columnsLayout(
              columns: {
                a!columnLayout(
                  contents: {
                    a!buttonArrayLayout(
                      buttons: {
                        a!buttonWidget(
                          label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{015775ca-76af-416a-9011-4c84f861f9b6}Cancel',
                          style: "LINK",
                          color: "#008294",
                          saveInto: a!save(
                            local!parseJson,
                            local!originalParseJson
                          )
                        ),
                        a!buttonWidget(
                          label: 'translation!{4813a583-da1f-481b-adb1-124a9b27e0a6}TTPK Translations.{1dcf6341-4906-4546-a0f1-074350544f5f}Save',
                          icon: "floppy-o",
                          style: "OUTLINE",
                          color: "#008294",
                          saveInto: {
                            a!save(
                              ri!sectionDetails,
                              a!forEach(
                                items: local!parseJson,
                                expression: a!map(
                                  sectionName: "Logistics Impact Levels",
                                  sectionValue: a!toJson(fv!item),
                                  createdBy: loggedInUser(),
                                  createdOn: now(),
                                  modifiedBy: loggedInUser(),
                                  modifiedOn: now(),
                                  isActive: true()
                                )
                              )
                            ),
                            a!writeRecords(
                              records: local!dataToWrite,
                              onSuccess: a!save(local!isNewRow, true),
                              onError: a!save(local!isNewRow, fv!error)
                            )
                          }
                        ),
                        
                      },
                      align: "END",
                      marginBelow: "NONE"
                    )
                  }
                )
              }
            )
          },
          showWhen: if(
            local!isLogisticsLevelCollapse,
            false,
            true
          ),
          showBorder: false()
        )
      }