Hossein Fallah
Hossein Fallah

Reputation: 2539

What is the proper way of loading a material UI dialog per item in list, on click of an action, in a dynamic way?

Let's say I have a list of customers, and I show them in a tabular format.

I can add some icons to the end of each customer row, to let user manage each row. Typical icons are delete and edit and icons like that.

Now I want to add an icon/action, that opens a dialog, passes some data from the row to the dialog, and gets data back from the dialog when it's closed.

In Angular, I would do it very easily. Because I could programmatically call a showDialog method or something similar to it, and pass parameters to it, and get the results. It's very dynamic.

In react + Material UI however, I'm stuck.

I want to render a dialog, and on the click of action of each row, I want to show that dialog and pass the data to it, and get data back from it.

What is the proper way of doing it?

Upvotes: 1

Views: 3993

Answers (1)

Louay Al-osh
Louay Al-osh

Reputation: 3405

Render list of data with view or edit dialog that can handler every item using React & MUI

The minimal requirements are:

  1. create one dialog component that can: display info, edit info and hit save
  2. a parent component that renders all data and have the open/close logic for the dialog, and can connect to the API in your preferable way

Here's a sample made with react, mui,and typescript

Define sample data and type


const tablesData = [
    { customerId: 1, customerName: 'customer1', address: 'some address 1' },
    { customerId: 2, customerName: 'customer2', address: 'some address 2' },
    { customerId: 3, customerName: 'customer3', address: 'some address 3' },
    { customerId: 4, customerName: 'customer4', address: 'some address 4' },
    { customerId: 5, customerName: 'customer5', address: 'some address 5' },
];

type Customer = typeof tablesData[number];


Defined a dialog component that can display an address of the customer which can be editable and submitted to the API later on if you want

interface EditCustomerDialogProps {
    open: boolean,
    closeHandler: () => void,
    customer: Customer,
    onSave: (customer: Customer) => void,
}

function EditCustomerDialog(props: EditCustomerDialogProps) {

    const { open, closeHandler, customer, onSave } = props;

    useEffect(function onCustomerChangeUpdateFormValues() {
        setAddress(customer.address);
    }, [customer]);

    const [address, setAddress] = useState('');
    const addressChangeHandler = useCallback(function _addressChangeHandler(event: any) {
        setAddress(event.target.value);
    }, []);


    const saveHandler = useCallback(function _saveHandler() {

        onSave({
            ...customer,
            address, // editable info,
        });

        closeHandler();
    }, [address]);


    return (
        <Dialog open={open} onClose={closeHandler}>

            <DialogTitle>
                {'Edit customer info'}
            </DialogTitle>

            <DialogContent dividers>
                <TextField
                    placeholder="address"
                    value={address}
                    onChange={addressChangeHandler}
                />
            </DialogContent>

            <DialogActions>
                <Button onClick={saveHandler}>
                    {'Save'}
                </Button>
                <Button onClick={closeHandler}>
                    {'Cancel'}
                </Button>
            </DialogActions>

        </Dialog>
    );
}

The parent component that controls the Dialog and can possible calls the API on save

function ComponentXYZ() {


    const [openEditDialgo, setOpenEditDialog] = useState(false);

    const closeDialogHandler = useCallback(function _handleClose() {
        setOpenEditDialog(false);
    }, []);

    const [selectedCustomer, setSelectedCustomer] = useState<Customer>({
        customerId: 0,
        customerName: '',
        address: '',
    });

    function customerEditHandler(customer: any) {
        setSelectedCustomer({ ...customer });
        setOpenEditDialog(true);
    }

    const saveHandler = useCallback(function _saveHandler(customer: Customer) {
        console.log({ customer });
    }, []);

    return (
        <Fragment>

            <EditCustomerDialog
                open={openEditDialgo}
                closeHandler={closeDialogHandler}
                customer={selectedCustomer}
                onSave={saveHandler}
            />

            <div>
                {
                    tablesData.map(customer => (
                        <Stack
                            key={customer.customerId}
                            direction="row">
                            <Typography>
                                {customer.customerName}
                            </Typography>
                            <Button onClick={() => customerEditHandler(customer)}>
                                {'edit info'}
                            </Button>
                        </Stack>
                    ))
                }
            </div>

        </Fragment>
    );

}

Upvotes: 5

Related Questions