Saving user input values in cdts from the editable grid

Certified Lead Developer

Hi,

I have editable grid having two columns one is readonly field for showing label and in the second column the user will enter the data. The data for this columns is getting from a local variable . The user can delete the rows and he add row upto 5 rows.

Now I have a cdt with fields like r1, r2, r3, r4, r5. Now I want to map the data entered by the user to cdt.

  Discussion posts and replies are publicly visible

Parents
  • 0
    Certified Lead Developer
    in reply to santoshd378

    This is a fairly straightforward case for an editable grid.  If you're using 17.2 or above, you can also do it without even needing to declare a sub-rule (at least for starters).  See below example.

    load(
      
      local!data: {
        {
          id: 1,
          label: "r1",
          value: ""
        },
        {
          id: 2,
          label: "r2",
          value: ""
        }
      },
      
      a!sectionLayout(
        label: "Test Editable Grid",
        contents: {
          a!paragraphField(
            label: "DEBUG",
            showWhen: false(),
            value: local!data,
            disabled: true()
          ),
          
          a!gridLayout(
            headerCells: {
              a!gridLayoutHeaderCell(label: "Label"),
              a!gridLayoutHeaderCell(label: "Value")
            },
            rows: a!forEach(
              local!data,
              a!gridRowLayout(
                contents: {
                  a!textField(
                    value: fv!item.label,
                    readOnly: true()
                  ),
                  a!textField(
                    value: fv!item.value,
                    saveInto: fv!item.value
                  )
                }
              )
            ),
            addRowLink: if(
              length(local!data) < 5,
              a!dynamicLink(
                label: "Add Row",
                saveInto: a!save(
                  local!data,
                  append(
                    local!data,
                    {
                      id: max(local!data.id)+1,
                      label: "r" & max(local!data.id)+1,
                      value: null()
                    }
                  )
                )
              ),
              null()
            )
          )
        }
      )
    )

  • 0
    Certified Lead Developer
    in reply to chandhinir

    Thanks for your reply - before I dig into your code I have a suggestion/request - maybe you could edit your post and put your sample code in a Code box - use the "insert" tool on the toolbar of the editor then choose "insert code", and paste your code there instead - that allows it to maintain formatting as well as not extending your comment window to extreme lengths.  Thanks!

  • load(
      local!selectedSections: {
        {
          "sectionId": 1,
          "sectionName": "Section1"
        },
        {
          "sectionId": 2,
          "sectionName": "Section2"
        }
      },
      local!selectedSectionQuestions: {
        {
          "pId": 1,
          "question": "e1",
          "orderNo": null,
          "refSectionId": 1
        },
        {
          "pId": 2,
          "question": "e2",
          "orderNo": null,
          "refSectionId": 1
        },
        {
          "pId": 3,
          "question": "p1",
          "orderNo": null,
          "refSectionId": 2
        },
        {
          "pId": 4,
          "question": "p2",
          "orderNo": null,
          "refSectionId": 2
        },
        {
          "pId": 5,
          "question": "p3",
          "orderNo": null,
          "refSectionId": 2
        }
      },
      local!selectedQuestions:type!question_cdt(),
      with(
        {a!forEach(
          items: local!selectedSections,
          expression: rule!TEST_uiDisplayQuestion(
            questions: local!selectedSectionQuestions,
            showWhen: 1,
            sections: fv!item,
            selectedSectionQuestions: local!selectedQuestions
          )
        )}
      )
    )
    --------------
    TEST_uiDisplayQuestion
    
    load(
      local!questions: index(
        ri!questions,
        wherecontains(
          tointeger(
            ri!sections.sectionId
          ),
          tointeger(
            ri!questions.refSectionId
          )
        ),
        {}
      ),
      local!sequence: a!forEach(
        items: local!questions,
        expression: null
      ),
      local!selectedIndices: tointeger(
        {}
      ),
      {
        a!sectionLayout(
          label: ri!sections.sectionName,
          contents: {
            a!gridLayout(
              label: "",
              headerCells: {
                a!gridLayoutHeaderCell(
                  label: "Available Questions"
                ),
                a!gridLayoutHeaderCell(
                  label: "Order No"
                )
              },
              columnConfigs: {
                a!gridLayoutColumnConfig(
                  width: "DISTRIBUTE",
                  weight: 1
                ),
                a!gridLayoutColumnConfig(
                  width: "NARROW"
                )
              },
              rows: a!forEach(
                items: local!questions,
                expression: a!gridRowLayout(
                  id: fv!item.pId,
                  contents: {
                    a!paragraphField(
                      label: "available questions",
                      labelPosition: "ABOVE",
                      value: fv!item.question,
                      readOnly: true
                    ),
                    a!integerField(
                      label: "orderNo",
                      labelPosition: "ABOVE",
                      value: fv!item.orderNo,
                      saveInto: {
                        fv!item.orderNo,
                        local!sequence[fv!index]
                      },
                      disabled: rule!APN_isBlank(
                        wherecontains(
                          tointeger(
                            fv!item.pId
                          ),
                          tointeger(
                            local!selectedIndices
                          )
                        )
                      ),
                      required: if(
                        contains(
                          tointeger(
                            local!selectedIndices
                          ),
                          wherecontains(
                            local!selectedIndices,
                            tointeger(
                              fv!item.pId
                            )
                          )
                        ),
                        true,
                        false
                      )
                    )
                  }
                )
              ),
              selectionValue: local!selectedIndices,
              selectionSaveInto: {
                local!selectedIndices,
                a!save(
                  local!selectedIndices,
                  reject(
                    fn!isnull(
                      _
                    ),
                    save!value
                  )
                ),
                a!forEach(
                  items: local!questions,
                  expression: {
                    a!save(
                      local!sequence[wherecontains(
                        tointeger(
                          fv!item.pId
                        ), tointeger(
                          local!selectedIndices
                        )
                      )],
                      if(
                        contains(
                          tointeger(
                            local!selectedIndices
                          ),
                          wherecontains(
                            tointeger(
                              fv!item.pId
                            ),
                            tointeger(
                              local!selectedIndices
                            )
                          )
                        ),
                        local!sequence[wherecontains(
                          tointeger(
                            fv!item.pId
                          ), tointeger(
                            local!selectedIndices
                          )
                        )],
                        null
                      )
                    )
                  }
                ),
                a!save(
                  ri!selectedQuestions,
                  index(
                    local!questions,
                    wherecontains(
                      tointeger(
                        local!selectedIndices
                      ),
                      tointeger(
                        local!questions.pId
                      )
                    ),
                    {}
                  )
                )
              },
              selectable: true,
              selectionRequired: true
            )
          }
        )
      }
    )


  • 0
    Certified Lead Developer
    in reply to chandhinir

    Are you saying questions won't have an Order value by default?  Why?

  • 0
    Certified Lead Developer
    in reply to chandhinir

    BTW, I have reproduced a partially-simplified version of your use case using my own new code.  In the case of this sample code it seems to work when I enter order numbers.  Please try this out and see if it helps you with your specific implementation.

    load(
      local!groceryList: {
        {
          id: 1,
          name: "Milk",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 2,
          name: "Tide Pods",
          orderNum: null(),
          category: "Cleaning Supplies"
        },
        {
          id: 3,
          name: "Eggs",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 4,
          name: "Paper Towels",
          orderNum: null(),
          category: "Cleaning Supplies"
        }
      },
      local!categories: union(local!grocerylist.category, local!groceryList.category),
      local!selectedItems: {},
      
      a!sectionLayout(
        contents: {
          
          a!forEach(
            local!categories,
            
            with(
              local!currentCategory: fv!item,
              a!gridLayout(
                label: fv!item,
                headerCells: {
                  a!gridLayoutHeaderCell(label: "Item"),
                  a!gridLayoutHeaderCell(label: "Order")
                },
                selectable: true(),
                selectionSaveInto: {
                  local!selectedItems
                },
                selectionValue: local!selectedItems,
                /*selectionStyle: "ROW_HIGHLIGHT",*/
                
                rows: a!forEach(
                  local!groceryList,
                  if(
                    fv!item.category = local!currentCategory,
                    a!gridRowLayout(
                      id: fv!item.id,
                      contents: {
                        a!richTextDisplayField(
                          label: "Item Name Display",
                          value: a!richTextItem(
                            text: fv!item.name
                          )
                        ),
                        a!textField(
                          label: "Order Number Editor",
                          value: fv!item.orderNum,
                          saveInto: {
                            fv!item.orderNum
                          },
                          disabled: not(
                            contains(
                              local!selectedItems,
                              fv!item.id
                            )
                          )
                        )
                      }
                      ),
                    {}
                  )
                )
              )
            )
          ),
            
          
          a!boxLayout(
            label: "DEBUG",
            style: "INFO",
            isCollapsible: true(),
            isInitiallyCollapsed: true(),
            contents: {
              a!paragraphField(
                value: "Selections: " & local!selectedItems & char(10) &
                  "CDT Data: " & local!groceryList
              )
            }
          )
        }
      )
    )

  • Hi Mike,

    Thanks!
    I tried the new code but grid selection is not retained when i select multiple sections.

  • 0
    Certified Lead Developer
    in reply to chandhinir

    Did you change anything from my example?  I have to double check but it seemed to work for me no matter which section I selected items from.  What happens wrong exactly?  Also can you confirm what Appian version you're on?

  • I am on Appian version 18.4.
    I was getting this error ( Expression evaluation error at function 'contains' [line 67]: Invalid types, can only act on data of the same type (Any Type, Number (Integer)). So did casting.

    There were two sections Food and Cleaning supplies.
    First I selected all items under food Section and enter the order no .When I selected the second section Cleaning supplies , the selection made in Food section lost  and only the selection in second grid retained.

  • 0
    A Score Level 2
    in reply to chandhinir

    load(
      local!groceryList: {
        {
          id: 1,
          name: "Milk",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 2,
          name: "Tide Pods",
          orderNum: null(),
          category: "Cleaning Supplies"
        },
        {
          id: 3,
          name: "Eggs",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 4,
          name: "Paper Towels",
          orderNum: null(),
          category: "Cleaning Supplies"
        }
      },
      local!categories: union(local!grocerylist.category, local!groceryList.category),
      local!selectedItems: {},
      
      a!sectionLayout(
        contents: {
          
          a!forEach(
            local!categories,
            
            with(
              local!currentCategory: fv!item,
              {
                a!gridLayout(
                  label: fv!item,
                  headerCells: {
                    a!gridLayoutHeaderCell(label: "Item"),
                    a!gridLayoutHeaderCell(label: "Order")
                  },
                  selectable: true(),
                  selectionSaveInto: {
                    local!selectedItems
                  },
                  selectionValue: local!selectedItems,
                  selectionStyle: "ROW_HIGHLIGHT",
                  
                  rows: a!forEach(
                    local!groceryList,
                    if(
                      fv!item.category = local!currentCategory,
                      a!gridRowLayout(
                        id: fv!item.id,
                        contents: {
                          a!richTextDisplayField(
                            label: "Item Name Display",
                            value: a!richTextItem(
                              text: fv!item.name
                            )
                          ),
                          a!textField(
                            label: "Order Number Editor",
                            value: fv!item.orderNum,
                            saveInto: {
                              fv!item.orderNum
                            },
                            disabled: not(
                              contains(
                                tointeger(local!selectedItems),
                                tointeger(fv!item.id)
                              )
                            )
                          )
                        }
                        ),
                      {}
                    )
                  )
                ),
                a!buttonLayout(
                  secondaryButtons: {
                    a!buttonWidget(
                      label:"Select All", 
                      saveInto: a!save(
                        local!selectedItems, 
                        append(
                          local!selectedItems,
                          index(
                            local!groceryList.id, 
                            wherecontains(local!currentCategory,touniformstring(property(local!groceryList, "category", {}))), 
                            {}
                          )
                        )
                      )
                    ), 
                    a!buttonWidget(
                      label:"Deselect All", 
                      saveInto: a!save(
                        local!selectedItems, 
                        remove(
                          local!selectedItems,
                          wherecontains(
                            index(
                              local!groceryList.id, 
                              wherecontains(local!currentCategory,touniformstring(property(local!groceryList, "category", {}))), 
                              {}
                            ), 
                            local!selectedItems
                          )
                        )
                      )
                    )
                  }
                )
              }
            )
          ),
          a!boxLayout(
            label: "DEBUG",
            style: "INFO",
            isCollapsible: true(),
            isInitiallyCollapsed: true(),
            contents: {
              a!paragraphField(
                value: "Selections: " & local!selectedItems & char(10) &
                  "CDT Data: " & local!groceryList
              )
            }
          )
        }
      )
    )

     One alternative solution to this issue is to add & change the selectionStyle to 'ROW_HIGHLIGHT" and add  SELECT/DE-SELECT ALL buttons below the grid(s) using the design Mike has already provided (which includes my changes - see code above). With the addition of the buttons, Mike's solution worked fine for me.

    It may also be helpful to add instructions so that users are made aware to literally select the rows they want to enable.

    I didn't see any viable solutions (in terms of complexity) that would work out when the checkbox to select all rows is de-selected, so I figured the above solution would be fine.

    One quirk you'd have to address though:

    1. When the user accidentally clicks the select all button but all the available rows, for the given grid, have already been selected (you'll understand if you refer to the debug field)

    Note: Just so you're aware, I am also using 18.4

  • 0
    Certified Lead Developer
    in reply to chandhinir

    Yeah, it turns out things get a little more tricky if you start using the "select all" checkboxes, which I was not originally testing as I was selecting individual rows by default.

    Please note that using the "select all" checkbox in one grid seems to deselect all items from the other grid as they both use a shared selected items list.  But manually checking individual items, it should work fine to select different items from different sections.  The following revision of my original code from above does some more careful typecasting on the indexes to avoid the error message you had reported even when the Select All boxes are utilized.

    load(
      local!groceryList: {
        {
          id: 1,
          name: "Milk",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 2,
          name: "Tide Pods",
          orderNum: null(),
          category: "Cleaning Supplies"
        },
        {
          id: 3,
          name: "Eggs",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 4,
          name: "Paper Towels",
          orderNum: null(),
          category: "Cleaning Supplies"
        }
      },
      local!categories: union(local!grocerylist.category, local!groceryList.category),
      local!selectedItems: tointeger({}),
      
      a!sectionLayout(
        contents: {
          
          a!forEach(
            local!categories,
            
            with(
              local!currentCategory: fv!item,
              a!gridLayout(
                label: fv!item,
                headerCells: {
                  a!gridLayoutHeaderCell(label: "Item"),
                  a!gridLayoutHeaderCell(label: "Order")
                },
                selectable: true(),
                selectionSaveInto: {
                  a!save(
                    local!selectedItems,
                    a!forEach(
                      save!value,
                      if(isnull(fv!item), {}, fv!item)
                    )
                  )
                },
                selectionValue: local!selectedItems,
                /*selectionStyle: "ROW_HIGHLIGHT",*/
                
                rows: a!forEach(
                  local!groceryList,
                  if(
                    fv!item.category = local!currentCategory,
                    a!gridRowLayout(
                      id: tointeger(fv!item.id),
                      contents: {
                        a!richTextDisplayField(
                          label: "Item Name Display",
                          value: a!richTextItem(
                            text: fv!item.name
                          )
                        ),
                        a!textField(
                          label: "Order Number Editor",
                          value: fv!item.orderNum,
                          saveInto: {
                            fv!item.orderNum
                          },
                          disabled: not(
                            contains(
                              tointeger(local!selectedItems),
                              tointeger(fv!item.id)
                            )
                          )
                        )
                      }
                      ),
                    {}
                  )
                )
              )
            )
          ),
            
          
          a!boxLayout(
            label: "DEBUG",
            style: "INFO",
            isCollapsible: true(),
            isInitiallyCollapsed: true(),
            contents: {
              a!paragraphField(
                value: "Selections: " & local!selectedItems & char(10) &
                  "CDT Data: " & local!groceryList
              )
            }
          )
        }
      )
    )

Reply
  • 0
    Certified Lead Developer
    in reply to chandhinir

    Yeah, it turns out things get a little more tricky if you start using the "select all" checkboxes, which I was not originally testing as I was selecting individual rows by default.

    Please note that using the "select all" checkbox in one grid seems to deselect all items from the other grid as they both use a shared selected items list.  But manually checking individual items, it should work fine to select different items from different sections.  The following revision of my original code from above does some more careful typecasting on the indexes to avoid the error message you had reported even when the Select All boxes are utilized.

    load(
      local!groceryList: {
        {
          id: 1,
          name: "Milk",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 2,
          name: "Tide Pods",
          orderNum: null(),
          category: "Cleaning Supplies"
        },
        {
          id: 3,
          name: "Eggs",
          orderNum: null(),
          category: "Food"
        },
        {
          id: 4,
          name: "Paper Towels",
          orderNum: null(),
          category: "Cleaning Supplies"
        }
      },
      local!categories: union(local!grocerylist.category, local!groceryList.category),
      local!selectedItems: tointeger({}),
      
      a!sectionLayout(
        contents: {
          
          a!forEach(
            local!categories,
            
            with(
              local!currentCategory: fv!item,
              a!gridLayout(
                label: fv!item,
                headerCells: {
                  a!gridLayoutHeaderCell(label: "Item"),
                  a!gridLayoutHeaderCell(label: "Order")
                },
                selectable: true(),
                selectionSaveInto: {
                  a!save(
                    local!selectedItems,
                    a!forEach(
                      save!value,
                      if(isnull(fv!item), {}, fv!item)
                    )
                  )
                },
                selectionValue: local!selectedItems,
                /*selectionStyle: "ROW_HIGHLIGHT",*/
                
                rows: a!forEach(
                  local!groceryList,
                  if(
                    fv!item.category = local!currentCategory,
                    a!gridRowLayout(
                      id: tointeger(fv!item.id),
                      contents: {
                        a!richTextDisplayField(
                          label: "Item Name Display",
                          value: a!richTextItem(
                            text: fv!item.name
                          )
                        ),
                        a!textField(
                          label: "Order Number Editor",
                          value: fv!item.orderNum,
                          saveInto: {
                            fv!item.orderNum
                          },
                          disabled: not(
                            contains(
                              tointeger(local!selectedItems),
                              tointeger(fv!item.id)
                            )
                          )
                        )
                      }
                      ),
                    {}
                  )
                )
              )
            )
          ),
            
          
          a!boxLayout(
            label: "DEBUG",
            style: "INFO",
            isCollapsible: true(),
            isInitiallyCollapsed: true(),
            contents: {
              a!paragraphField(
                value: "Selections: " & local!selectedItems & char(10) &
                  "CDT Data: " & local!groceryList
              )
            }
          )
        }
      )
    )

Children
No Data