Search code examples
javascriptreactjsspfxfluent-uifluentui-react

How to group items in a DetailsList using Fluent UI


I'm attempting to group items in a DetailsList using Fluent UI controls. The example they give is this for the grouping:

const groups = [
        { key: 'groupred0', name: 'Color: "red"', startIndex: 0, count: 2, level: 0 },
        { key: 'groupgreen2', name: 'Color: "green"', startIndex: 2, count: 0, level: 0 },
        { key: 'groupblue2', name: 'Color: "blue"', startIndex: 0, count: 3, level: 0 },
    ];

I have a list of items. Each items has an InitialAssessment number. Multiple items can have the same InitialAssessment number. This is how I want it grouped. e.g: enter image description here The red boxes demonstrate how I want it grouped by Initial Assessment. This is what I've tried so far:

 const [initialAssessments, setInitialAssessments] = useState([]);
 const [theGroups, setTheGroups] = useState([]);

///
const getInitialAssessments = React.useCallback(() => {
        const result = [];
        const map = new Map();
        for (const item of assessments) {
            if (!map.has(item.InitialAssessment)) {
                map.set(item.InitialAssessment, true);
                result.push({
                    InitialAssessment: item.InitialAssessment,
                    name: item.Business,
                });
            }
        }
        setInitialAssessments(result);
        let arr1 = assessments;
        let arr2 = arr1.map(v => ({
            key: v.Id, 
            name: v.InitialAssessment, 
            startIndex: 0, 
            count: result.length, //This is wrong for a start!
            level: 0
        })); 
        setTheGroups(arr2);
    }
////////

 <DetailsList className={styles.DetailsList}
   items={allAssessments.slice((ListPage - 1) * 50, ((ListPage * 50)))}
   columns={_detailsListColumns}
   groups={theGroups}
   selection={selection}
   onRenderItemColumn={_onRenderColumn}
  />


But I've hugely overthought it and now got into a mess. The above groups things incorrectly. I hope the above is enough to give you an idea of what I want and doesn't cloud the waters!


Solution

  • Let's say you have the following data structure from Backend like inside Snippet. Important part is to sort items by initialAssessment before grouping.

    const data = [
      {
        id: 1,
        initialAssessment: 1,
        name: "Title",
        business: "Walmart",
      },
      {
        id: 2,
        initialAssessment: 1,
        name: "Title",
        business: "Walmart",
      },
      {
        id: 3,
        initialAssessment: 2,
        name: "Title",
        business: "Tesco",
      },
      {
        id: 4,
        initialAssessment: 2,
        name: "Title",
        business: "Tesco",
      },
      {
        id: 5,
        initialAssessment: 2,
        name: "Title",
        business: "Tesco",
      },
      {
        id: 6,
        initialAssessment: 3,
        name: "Title",
        business: "Whole Foods",
      },
    ];
    
    // It's importatnt to sort data!
    const sortedData = [...data].sort(
      (a, b) => a.initialAssessment - b.initialAssessment
    );
    
    const groups = sortedData.reduce((acc, cur) => {
      const { initialAssessment, name } = cur;
      const group = {
        key: initialAssessment,
        name: `Initial Assessment ${initialAssessment}`,
        startIndex: 0,
        count: 1,
        isCollapsed: true,
      };
      if (acc.length === 0) {
        acc.push(group);
        return acc;
      } else if (acc[acc.length - 1].key !== cur.initialAssessment) {
        const { count, startIndex } = acc[acc.length - 1];
        acc.push({
          ...group,
          startIndex: count + startIndex,
        });
        return acc;
      }
      acc[acc.length - 1].count++;
      return acc;
    }, []);
    
    console.log(groups)

    Here you are full working Codepen example.

    Snippet Codepen.