Skip to main content

Edit Modal (Save/Cancel)

Pattern for if you want to have a modal that can either add a new instance of an object or edit an existing one. The parent copy of the object won't be updated until you press "Save".

Live Editor
function App() {
    interface IPerson extends ICopy, IDefault {
        name: string;
        age: number;
    }

    const copy = function copy(person: IPerson): IPerson {
        return {
            name: person.name,
            age: person.age
        };
    }

    const getDefault = function getDefault(person: IPerson): IPerson {
        return {
            name: "",
            age: 0
        };
    }

    //
    // Edit Modal
    //

    interface IEditModalProps {
        person: IPerson | null;
        onSave: (person?: IPerson) => void;
        onCancel: () => void;
    }

    function EditModal(props: IEditModalProps) {
        const [localPerson, setLocalPerson] = useState<IPerson | undefined>(undefined);

        useEffect(() => {
            if (props.person) {
                setLocalPerson(copy(props.person));
            } else {
                setLocalPerson(getDefault());
            }
        }, [props.person, setLocalPerson]);

        const onPropertyChange = useCallback((property: string, value: any) => {
            setLocalPerson({ ...localPerson, [property]: value });
        }, [localPerson]);

        if (!localPerson) { return null; }

        return (
            <div>
                Local Person: <code>{JSON.stringify(localPerson)}</code>
                <br />

                <input type="text" value={localPerson.name}
                    onChange={(e) => {
                        setLocalPerson({ ...localPerson, name: e.target.value })
                    }}
                /><br />

                <input type="number" value={localPerson.age}
                    onChange={(e) => {
                        setLocalPerson({ ...localPerson, age: e.target.value })
                    }}
                /><br />

                <button type="button" onClick={()=> {
                    props.onSave(localPerson);
                }}>Save</button>{' '}
                <button type="button" onClick={props.onCancel}>Cancel</button>
            </div>
        );
    }

    //
    // App
    //

    const [person, setPerson] = useState<IPerson | null>({ name: "John", age: 30 });
    // const [person, setPerson] = useState<IPerson | null>(null);

    return (
        <div>
            Parent Copy: <code>{JSON.stringify(person)}</code><br />
            <EditModal person={person} onSave={setPerson} />
        </div>
    )
}
Result
Loading...