Frontend Serverless with React and GraphQL
Start at the beginning and work your way through this project. The code for each step as well as the finished project can be found in the Github repository.
34. Add a Delete Ingredient Button
Objective: Create a delete button for the GenerateIngredients component that will allow users to remove ingredients from the list.
We need to create a delete button for each ingredient to ensure that users can remove unneeded ingredients from the list. We can add an additional column by concatinating a delete column onto the list of columns that we already have.
components/GenerateIngredients.tsx
import { Row, Col, Button, Table, Input, Dropdown } from 'antd';import { MenuList } from './MenuList';import * as _ from 'lodash';type IngredientsProps = {names?: string[];values?: [{ amount: string; unit: string; type: string }];handleAddIngredient: (event: any) => void;handleDeleteIngredient: (event: any) => void;handleInputChange: (event: any) => void;handleDropdownChange: (event: any) => void;};const units = ['-', 'ounce', 'lb', 'cup', 'tb', 'tsp', 'g', 'kg'];export const GenerateIngredients = ({names,values,handleAddIngredient,handleDeleteIngredient,handleInputChange,handleDropdownChange,}: IngredientsProps) => {const columns = _.concat(names.map((name) => ({title: `${name}`,key: `${name}`,render: (ingredient, _record, index: number) => {return name === 'unit' ? (<Dropdownoverlay={<MenuListiterableList={units}name={`ingredients[${index}].${name}`}handleDropdownChange={handleDropdownChange}/>}placement="bottomLeft"><Button>{ingredient[name]}</Button></Dropdown>) : (<Inputvalue={ingredient[name]}placeholder={`${name}`}name={`ingredients[${index}].${name}`}onChange={handleInputChange}/>);},})),[{title: 'delete',key: 'delete',render: (_ingredient, _record, index: number) => (<ButtononClick={handleDeleteIngredient}type="danger"shape="circle"size="small"name={`${index}`}>-</Button>),},],);return (<><Row><Col span={12} offset={6}><p><ButtononClick={handleAddIngredient}type="primary"shape="circle"size="small">+</Button>ingredients:</p></Col></Row>{values.length > 0 ? (<Row><Col span={12} offset={6}><TabledataSource={values}columns={columns}pagination={{ pageSize: 25 }}/></Col></Row>) : null}</>);};
The delete button will call a delete ingredient handler, so we need to now create this in the submitForm
hook and pass it into the <GenerateIngredients>
component
utils/submitForm.ts
import { useState } from 'react';import * as _ from 'lodash';export const submitForm = (initialValues, callback) => {const [inputs, setInputs] = useState(initialValues);const handleInputChange = (event) => {event.persist();setInputs((inputs) => {const newInputs = _.cloneDeep(inputs);_.set(newInputs, event.target.name, event.target.value);return newInputs;});};const handleDropdownChange = (event) => {setInputs((inputs) => {const newInputs = _.cloneDeep(inputs);_.set(newInputs, event.item.props.title, event.key);return newInputs;});};const handleAddIngredient = (event) => {event.persist();setInputs((inputs) => {const sortedIngredients = _.sortBy(inputs.ingredients, ['key']);const key =sortedIngredients.length > 0? sortedIngredients[sortedIngredients.length - 1].key + 1: 0;return {...inputs,ingredients: _.concat(inputs.ingredients, [{ key, amount: '', unit: '-', type: '' },]),};});};const handleDeleteIngredient = (event) => {console.log('deleted');event.persist();const position = parseInt(event.target.name);setInputs((inputs) => ({...inputs,ingredients: _.filter(inputs.ingredients,(_i, index) => index !== position,),}));};const handleSubmit = () => {callback();setInputs(() => ({ ...initialValues }));};return {inputs,handleSubmit,handleInputChange,handleAddIngredient,handleDeleteIngredient,handleDropdownChange,};};