multilevel nested list in material-ui next
Asked Answered
S

2

6

I'd like to create multilevel nested list to display the menu on the left side - - very similar as on oficial site: https://material-ui-next.com/. data source is in JSON where for each item there's also information about parent item and some other data - - this is the example:

{
    "task_number": 1201092,
    "task": "Monthly Cash Flow from Deliveries",
    "task_parent_number": 1201090,
    "task_parent": "Wholesale Cash Flow"
},
{
    "task_number": 1201095,
    "task": "Monthly Cash Flow from Fix Amounts",
    "task_parent_number": 1201090,
    "task_parent": "Wholesale Cash Flow"
},
{
    "task_number": 1201100,
    "task": "Wholesale Positions",
    "task_parent_number": 1200007,
    "task_parent": "Wholesale Contract Portfolio"
},
{
    "task_number": 1201200,
    "task": "All Wholesale Positions",
    "task_parent_number": 1201100,
    "task_parent": "Wholesale Positions"
}

I'am able to create an object with various nested elements - children - if they exist with followin function:

function getNestedChildren(arr, parent) {
  var out = [];
  for (var i in arr) {
    if (arr[i].task_parent_number == parent) {
      //console.log(i, arr[i].task_parent_number, arr[i].task_number);
      var children = getNestedChildren(arr, arr[i].task_number);
      if (children.length) {
        arr[i].children = children;
      }
      out.push(arr[i]);
    }
  }

  return out;
}

I've been following instructions for creating a nested list and importing it here: https://material-ui-next.com/demos/lists/#nested-list

..but I am not able to create a menu with nested elements as desired . . if someone can point me in the right direction would be great..

Syllabi answered 4/2, 2018 at 12:4 Comment(0)
S
6

OK, i got this to work combining these 2 parts:

  1. React example recursive render: https://gist.github.com/nkvenom/bf7b1adfe982cb47dee3
  2. Material List guide here - https://medium.com/@ali.atwa/getting-started-with-material-ui-for-react-59c82d9ffd93
Syllabi answered 7/2, 2018 at 19:42 Comment(2)
Very useful. Thank you :)Petard
I'm using the same approach, but one thing I'm struggling with is, I'm using hooks and I'm getting a problem, when I click the parent item, everything works fine, but when I click on an child containing grandchild, Whole menu returns to "Expandless" state, meaning it closes, how can I achieve same with hooks?Bracteole
B
0

There is mui component.

I add recursion to the last example.

import type { SvgIconProps } from '@mui/material/SvgIcon';

import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import TreeView, { TreeViewProps } from '@mui/lab/TreeView';
import TreeItem, { TreeItemProps, treeItemClasses } from '@mui/lab/TreeItem';
import Typography from '@mui/material/Typography';
// import DeleteIcon from '@mui/icons-material/Delete';
// import Label from '@mui/icons-material/Label';
// import SupervisorAccountIcon from '@mui/icons-material/SupervisorAccount';
// import InfoIcon from '@mui/icons-material/Info';
// import ForumIcon from '@mui/icons-material/Forum';
// import LocalOfferIcon from '@mui/icons-material/LocalOffer';
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import ArrowRightIcon from '@mui/icons-material/ArrowRight';

declare module 'react' {
    interface CSSProperties {
        '--tree-view-color'?: string;
        '--tree-view-bg-color'?: string;
    }
}

type StyledTreeItemProps = TreeItemProps & {
    bgColor?: string;
    color?: string;
    labelIcon?: React.ElementType<SvgIconProps>;
    labelInfo?: React.ReactNode;
    labelText: string;
};

type RecursiveStyledTreeItemProps = StyledTreeItemProps & {
    childrenProps?: RecursiveStyledTreeItemProps[]
}

const StyledTreeItemRoot = styled(TreeItem)(({ theme }) => ({
    color: theme.palette.text.secondary,
    [`& .${treeItemClasses.content}`]: {
        color: theme.palette.text.secondary,
        borderTopRightRadius: theme.spacing(2),
        borderBottomRightRadius: theme.spacing(2),
        paddingRight: theme.spacing(1),
        fontWeight: theme.typography.fontWeightMedium,
        '&.Mui-expanded': {
            fontWeight: theme.typography.fontWeightRegular,
        },
        '&:hover': {
            backgroundColor: theme.palette.action.hover,
        },
        '&.Mui-focused, &.Mui-selected, &.Mui-selected.Mui-focused': {
            backgroundColor: `var(--tree-view-bg-color, ${theme.palette.action.selected})`,
            color: 'var(--tree-view-color)',
        },
        [`& .${treeItemClasses.label}`]: {
            fontWeight: 'inherit',
            color: 'inherit',
        },
    },
    [`& .${treeItemClasses.group}`]: {
        marginLeft: 0,
        [`& .${treeItemClasses.content}`]: {
            paddingLeft: theme.spacing(2),
        },
    },
}));

const RecursiveStyledTreeItem = ({ childrenProps, ...p }: RecursiveStyledTreeItemProps) => childrenProps
    ? <RecursiveStyledTreeItem {...p}>
        {
            childrenProps.map(cP => <RecursiveStyledTreeItem
                key={cP.nodeId}
                {...cP}
            />)
        }
    </RecursiveStyledTreeItem>
    : < StyledTreeItem {...p} />

function StyledTreeItem(props: StyledTreeItemProps) {
    const {
        bgColor,
        color,
        labelIcon: LabelIcon = null,
        labelInfo = null,
        labelText,
        ...other
    } = props;

    return (
        <StyledTreeItemRoot
            label={
                <Box sx={{ display: 'flex', alignItems: 'center', p: 0.5, pr: 0 }}>
                    {
                        LabelIcon && <Box component={LabelIcon} color="inherit" sx={{ mr: 1 }} />
                    }
                    <Typography variant="body2" sx={{ fontWeight: 'inherit', flexGrow: 1 }}>
                        {labelText}
                    </Typography>
                    {
                        labelInfo && <Typography variant="caption" color="inherit">
                            {labelInfo}
                        </Typography>
                    }
                </Box>
            }
            style={{
                '--tree-view-color': color,
                '--tree-view-bg-color': bgColor,
            }}
            {...other}
        />
    );
}

export default function CustomTreeView({ treeViewProps, items }: {
    treeViewProps: Partial<TreeViewProps>
    items: RecursiveStyledTreeItemProps[]
}) {
    return (
        <TreeView
            // defaultExpanded={['3']}
            defaultCollapseIcon={<ArrowDropDownIcon />}
            defaultExpandIcon={<ArrowRightIcon />}
            defaultEndIcon={<div style={{ width: 24 }} />}
            sx={{ height: 264, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
            {...treeViewProps}
        >
            {items.map(item => <RecursiveStyledTreeItem
                key={item.nodeId}
                {...item}
            />)}
        </TreeView>
    );
}

There is mui-tree-select

Blindstory answered 22/2, 2023 at 2:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.