Documentation

Report Edit

Stateful Tree Grid

The following example shows how to make a stateful tree grid component with some common tree functionalities. This way, the state (expanded folders) of the grid will be preserved, even if we reload grid data. Keep in mind that a record's state will be preserved only if the value of the record's expanded property after reload is nullish (null or undefined).

To make grid stateful, restoreExpandedNodesOnLoad property should be set to true on TreeAdapter. Additionally, keyField property on either Grid or data adapter has to be specified.

The Code also showcases usage of some builtin Cx functions for easier tree manipulation, like updateTree and removeTreeNodes.

NamePhoneCityNotified
Kareem Smith
161-421-6509New LillyhavenNo
Armando Stiedemann
648-756-5595LethabergNo
Raven Wuckert
287-032-2866New HubertNo
Brielle Huels
970-716-3391South ChanceNo
Annamarie Larson
087-861-1860South DiannachesterNo
Ally Hickle
818-660-8495New OvaNo
Junior Upton
144-267-0241OletamouthNo
Marcelle Sanford
167-062-4816HaleymouthNo
Anjali Murazik
170-911-3807MaciportNo
Dasia Kiehn
349-382-7832Port GaetanohavenNo
Maurine Kemmer
567-475-3896ReillybergNo
Demetris Carter
819-330-4209North KayleymouthNo
NamePhoneCityNotified
ControllerIndex
<div controller={PageController}>
   <FlexRow spacing style="margin-bottom: 10px">
      <Button onClick="load" text="Reload" mod="primary" />
      <Button
         onClick="expandCollapseTree"
         text="Expand All"
         text-expr="{$page.treeExpanded} ? 'Collapse All' : 'Expand All'"
      />
      <Button onClick="addFolder" text="Add Folder" />
      <Button onClick="addLeaf" text="Add File" />
      <Button onClick="deleteRecord" text="Delete" mod="danger" disabled-expr="!{$page.selection}" />
   </FlexRow>
   <Grid
      emptyText="Loading data..."
      records-bind="$page.data"
      mod="tree"
      style={{
         width: "100%",
         opacity: expr("{$page.loading} ? 0.4 : 1"),
         height: 400,
      }}
      scrollable={true}
      dataAdapter={{
         type: TreeAdapter,
         restoreExpandedNodesOnLoad: true,
      }}
      keyField='recordId'
      selection={{ type: KeySelection, bind: "$page.selection", keyField: 'recordId' }}
      columns={[
         {
            header: "Name",
            field: "fullName",
            sortable: true,
            items: (
               <cx>
                  <TreeNode
                     expanded-bind="$record.$expanded"
                     leaf-bind="$record.$leaf"
                     level-bind="$record.$level"
                     loading-bind="$record.$loading"
                     text-bind="$record.fullName"
                     icon-bind="$record.icon"
                  />
               </cx>
            ),
         },
         { header: "Phone", field: "phone" },
         { header: "City", field: "city", sortable: true },
         {
            header: "Notified",
            field: "notified",
            sortable: true,
            value: { expr: '{$record.notified} ? "Yes" : "No"' },
         },
      ]}
      onRowContextMenu={(e, instance) => {
         openContextMenu(
            e,
            <cx>
               <Menu>
                  <MenuItem onClick="deleteRecordFromContextMenu" autoClose>
                     Delete
                  </MenuItem>
                  <PureContainer visible-expr="!{$record.$leaf}">
                     <MenuItem onClick="addFolderFromContextMenu" autoClose>
                        Add Folder
                     </MenuItem>
                     <MenuItem onClick="addLeafFromContextMenu" autoClose>
                        Add File
                     </MenuItem>
                  </PureContainer>
               </Menu>
            </cx>,
            instance
         );
      }}
   />
</div>
Copied!Cx Fiddle