Nested Grid

Hi Experts,

I have a user requirement for which I need to create a Nested Grid. Structure is as given below

{
{
Index:1,
{ id: 1, text: "abc", fee:123},
{ id: 2, text: "def", fee:1123},
},

{
Index:2,
{ id: 1, text: "xyz", fee:123}
{ id: 2, text: "xxx", fee:112},
{ id: 3, text: "yyy", fee:133}
}
}

For this I have created

CDT 1 have fields as below:

where field "grid" is of type cdt 2 which have structure as below

  

Now I have to deign the grid in such a way that I can add multiple editable grid and store the data entered in grid respectively.

I'm trying to use below code snippet but not able to store the values entered in the grid.

a!localVariables(
  local!counter: 0,
  local!grid: ri!multiFeeGrid.grid,
  {
    a!columnsLayout(
      columns: {
        a!columnLayout(
          contents: {
            a!linkField(
              label: "",
              links: a!dynamicLink(
                label: "Add Amendments",
                saveInto: {
                  a!save(local!counter, local!counter + 1),
                  a!save(
                    ri!multiFeeGrid,
                    append(
                      ri!multiFeeGrid,
                      'type!{urn:com:appian:types:CS}CS_multiLicenseFee'(
                        index:local!counter,
                        grid:local!grid
                      )
                    )
                  )
                }
              )
            )
          }
        ),
        a!columnLayout(
          contents: {
            a!linkField(
              label: "",
              links: a!dynamicLink(
                label: "Remove Amendments",
                saveInto: { 
                  a!save(local!counter, local!counter - 1),
                }
              )
            )
          }
        )
      }
    ),
    a!forEach(
      items: enumerate(local!counter),
      expression: {
        a!cardLayout(
          contents: {
            a!sideBySideLayout(
              items: {
                a!sideBySideItem(
                  width: "MINIMIZE",
                  item: a!richTextDisplayField(
                    value: { 
                      a!richTextItem(
                        text: "The fees payable by the Licensee as at the Commencement Date are as follows: ", 
                      )            
                    }
                  )
                )
              }
            ),
            a!columnsLayout(
              columns: {
                a!columnLayout(
                  width: "WIDE",
                  contents: a!gridLayout(
                    label: "",
                    labelPosition: "ABOVE",
                    emptyGridMessage: "No Data Available",
                    headerCells: {
                      a!gridLayoutHeaderCell(label: "Items"),
                      a!gridLayoutHeaderCell(label: "Fee (in $ per year)"),
                      a!gridLayoutHeaderCell(label: ""),

                    },
                    columnConfigs: {
                      a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 1),
                      a!gridLayoutColumnConfig(width: "DISTRIBUTE", weight: 1),
                      a!gridLayoutColumnConfig(width: "ICON")
                    },
                    rows: {
                      a!forEach(
                        items: local!grid,
                        expression: a!gridRowLayout(
                          contents: {
                            a!textField(
                              value: fv!item.text,
                              saveInto: { 
                                fv!item.text ,
                                a!save(
                                  ri!multiFeeGrid,
                                  'type!{urn:com:appian:types:CS}CS_multiLicenseFee'(
                                    index:local!counter,
                                    grid:local!grid
                                  )
                                )
                              },
                              refreshAfter: "KEYPRESS",
                              required: true(),

                            ),
                            a!floatingPointField(
                              value: fv!item.fee,
                              saveInto: {                                
                                fv!item.fee,
                                a!save(
                                  ri!multiFeeGrid,
                                  'type!{urn:com:appian:types:CS}CS_multiLicenseFee'(
                                    index:local!counter,
                                    grid:local!grid
                                  )
                                )
                              },
                              refreshAfter: "KEYPRESS",
                              required: true()
                            ),
                            a!richTextDisplayField(
                              value: {
                                a!richTextIcon(
                                  icon: "close",
                                  link: {
                                    a!dynamicLink(
                                      value: fv!index,
                                      saveInto: {
                                        a!save(
                                          local!grid,
                                          remove(local!grid, save!value),                                  
                                        )                         
                                      }
                                    )
                                  },
                                  linkStyle: "STANDALONE",

                                )
                              }
                            )
                          }
                        )
                      )
                    },
                    selectionSaveInto: {},
                    addRowlink: a!dynamicLink(
                      label: "Add Item",
                      value: {
                        'type!{urn:com:appian:types:TCA}LicenseFees'(text: "", fee: null)
                      },
                      saveInto: {
                        a!save(
                          local!grid,
                          append(local!grid, save!value)
                        ),
                        a!save(
                          ri!multiFeeGrid,
                          'type!{urn:com:appian:types:CS}CS_multiLicenseFee'(
                            index:local!counter,
                            grid:local!grid
                          )
                        )
                      }
                    ),
                    validations: {},
                    shadeAlternateRows: true
                  )
                )
              }
            ),
            a!sideBySideLayout(
              items: {
                a!sideBySideItem(
                  width: "MINIMIZE",
                  item: a!richTextDisplayField(
                    value: {
                      "Total License Fees payable annually at the Commencement Date: ",
                      a!richTextItem(
                        text: dollar(
                          if(
                            rule!APN_isBlank(local!grid),
                            0,
                            sum(local!grid.fee)
                          )
                        ),
                        style: "STRONG"
                      ),
                      a!richTextItem(
                        text:", or payment of equal monthly instalments of ",            
                      ),
                      a!richTextItem(
                        text: dollar(
                          if(
                            rule!APN_isBlank(local!grid),
                            0,
                            sum(local!grid.fee)/12
                          )
                        ),
                        style: "STRONG"
                      )
                    }
                  )
                )
              }
            )            
          }
        )
      }
    )
  }
)

  Discussion posts and replies are publicly visible

Parents
  • +1
    Certified Lead Developer

    I've whipped up this quick and very-slightly-simplified demo that should show how to structure this in general.  The main change you'd need to make is swapping back in your actual nested CDT, instead of my fake local variable (but this way anyone can copy/paste and run this code).

    I believe i've identified a primary potential point of confusion which is, whenever you save into one of the lower row values, you'll need to save it up to the main original CDT value instead of the local copy.  This gets tricky with a nested a!forEach() call, but this can be solved with strategic use of placeholder local variables within each loop.

    a!localVariables(
      
      local!nestedCdt: { /* you will swap out this value with your nested CDT rule input */
        {
          index: 1,
          grid: {
            {id: 1, text: "abc"},
            {id: 2, text: "qwer"}
          }
        },
        {
          index: 2,
          grid: {
            {id: 1, text: "def"},
            {id: 2, text: "zxcv"},
            {id: 3, text: "12345"}
          }
        }
      },
      local!currentCount: max(local!nestedCdt.index), /* this variable should mainly be informative, probably not the active element you loop over */
      local!maxGrids: 6,
      local!fullGrids: local!currentCount >= local!maxGrids,
      
      a!sectionLayout(
        label: "Demonstration Multi-Grid for Nested CDT",
        contents: {
          a!richTextDisplayField(  /* use this instead of a!linkField() */
            value: a!richTextItem(
              text: {
                a!richTextIcon(icon: "plus-circle"),
                " Add Grid " & local!currentCount + 1
              },
              size: "MEDIUM",
              linkStyle: "STANDALONE",
              style: if(local!fullGrids, "EMPHASIS", null()),
              color: if(local!fullGrids, "SECONDARY", null()),
    
              link: a!dynamicLink(
                showWhen: not(local!fullGrids),
                saveInto: {
                  a!save(
                    local!nestedCdt,
                    append(
                      local!nestedCdt,
                      {
                        index: local!currentCount + 1,
                        grid: {}
                      }
                    )
                  )
                }
              )
            )
          ),
          
          a!forEach(
            local!nestedCdt,
            a!localVariables(
              local!currentEntry: fv!item,
              local!parentIndex: fv!index,
              a!gridLayout(
                label: "Grid for Index " & local!currentEntry.index,
                headerCells: {
                  a!gridLayoutHeaderCell(label: "Id"),
                  a!gridLayoutHeaderCell(label: "Text")
                },
                rows: a!forEach(
                  local!currentEntry.grid,
                  a!gridRowLayout(
                    id: local!currentEntry.index,
                    contents: {
                      a!richTextDisplayField(
                        value: fv!item.id
                      ),
                      a!textField(
                        label: "Text Column",
                        value: fv!item.text,
                        saveInto: {
                          /*fv!item.text*/
                          /* the SaveInto here will need to save straight to the parent CDT, not the local copy */
                          a!save(
                            local!nestedCdt[local!parentIndex].grid[fv!index].text,
                            save!value
                          )
                        }
                      )
                    }
                  )
                ),
                addRowLink: a!dynamicLink(
                  label: "Add Row",
                  saveInto: {
                    a!save(
                      fv!item.grid,
                      append(
                        fv!item.grid,
                        {
                          id: if(
                            isnull(property(fv!item.grid, "id", null())),
                            1,
                            max(fv!item.grid.id) + 1
                          ),
                          text: "[new row added]"
                        }
                      )
                    )
                  }
                )
              )
            )
          )
        }
      )
    )

Reply
  • +1
    Certified Lead Developer

    I've whipped up this quick and very-slightly-simplified demo that should show how to structure this in general.  The main change you'd need to make is swapping back in your actual nested CDT, instead of my fake local variable (but this way anyone can copy/paste and run this code).

    I believe i've identified a primary potential point of confusion which is, whenever you save into one of the lower row values, you'll need to save it up to the main original CDT value instead of the local copy.  This gets tricky with a nested a!forEach() call, but this can be solved with strategic use of placeholder local variables within each loop.

    a!localVariables(
      
      local!nestedCdt: { /* you will swap out this value with your nested CDT rule input */
        {
          index: 1,
          grid: {
            {id: 1, text: "abc"},
            {id: 2, text: "qwer"}
          }
        },
        {
          index: 2,
          grid: {
            {id: 1, text: "def"},
            {id: 2, text: "zxcv"},
            {id: 3, text: "12345"}
          }
        }
      },
      local!currentCount: max(local!nestedCdt.index), /* this variable should mainly be informative, probably not the active element you loop over */
      local!maxGrids: 6,
      local!fullGrids: local!currentCount >= local!maxGrids,
      
      a!sectionLayout(
        label: "Demonstration Multi-Grid for Nested CDT",
        contents: {
          a!richTextDisplayField(  /* use this instead of a!linkField() */
            value: a!richTextItem(
              text: {
                a!richTextIcon(icon: "plus-circle"),
                " Add Grid " & local!currentCount + 1
              },
              size: "MEDIUM",
              linkStyle: "STANDALONE",
              style: if(local!fullGrids, "EMPHASIS", null()),
              color: if(local!fullGrids, "SECONDARY", null()),
    
              link: a!dynamicLink(
                showWhen: not(local!fullGrids),
                saveInto: {
                  a!save(
                    local!nestedCdt,
                    append(
                      local!nestedCdt,
                      {
                        index: local!currentCount + 1,
                        grid: {}
                      }
                    )
                  )
                }
              )
            )
          ),
          
          a!forEach(
            local!nestedCdt,
            a!localVariables(
              local!currentEntry: fv!item,
              local!parentIndex: fv!index,
              a!gridLayout(
                label: "Grid for Index " & local!currentEntry.index,
                headerCells: {
                  a!gridLayoutHeaderCell(label: "Id"),
                  a!gridLayoutHeaderCell(label: "Text")
                },
                rows: a!forEach(
                  local!currentEntry.grid,
                  a!gridRowLayout(
                    id: local!currentEntry.index,
                    contents: {
                      a!richTextDisplayField(
                        value: fv!item.id
                      ),
                      a!textField(
                        label: "Text Column",
                        value: fv!item.text,
                        saveInto: {
                          /*fv!item.text*/
                          /* the SaveInto here will need to save straight to the parent CDT, not the local copy */
                          a!save(
                            local!nestedCdt[local!parentIndex].grid[fv!index].text,
                            save!value
                          )
                        }
                      )
                    }
                  )
                ),
                addRowLink: a!dynamicLink(
                  label: "Add Row",
                  saveInto: {
                    a!save(
                      fv!item.grid,
                      append(
                        fv!item.grid,
                        {
                          id: if(
                            isnull(property(fv!item.grid, "id", null())),
                            1,
                            max(fv!item.grid.id) + 1
                          ),
                          text: "[new row added]"
                        }
                      )
                    )
                  }
                )
              )
            )
          )
        }
      )
    )

Children
No Data