I have a react component where I submit a form using formik
import { Field, Form, FormikProps, Formik } from "formik";
import {
Combobox,
ComboboxInput,
ComboboxOptionText,
ComboboxPopover,
ComboboxOption,
ComboboxList,
} from "@reach/combobox";
import {
createShop,
getMerchants,
getActiveMerchants,
} from "../../../request/shop";
import { useState } from "react";
import { useQuery } from "react-query";
import "styled-components/macro";
import Loader from "react-spinners/BarLoader";
import { useDebounce } from "use-debounce";
import { toast } from "react-toastify";
import { UploadImage } from "../../../common/UploadImage";
import { removeaSinglItem } from "../../../utils/helper";
import { KeyPerson } from "../component/KeyPerson";
import { CategoryHead } from "../component/CategoryHead";
import { BDM } from "../component/BDM";
import { KAM } from "../component/KAM";
import { VM } from "../component/VM";
import ImageUploadCrop from "../../../common/ImageUploadCrop";
import MapViewWithSearch from "../../../common/MapViewWithSearch";
import { Button } from "../../../common/Button";
export function CreateShop(): JSX.Element {
const [searchMerchantText, setSearchMerchantText] = useState<string>("");
const [selectedMerchant, setSelectedMerchant] = useState<{
merchant_name: string;
merchant_code: string;
}>({ merchant_name: "", merchant_code: "" });
const [throttledMerchantText] = useDebounce(searchMerchantText, 500);
const queryMerchantSearch = useQuery(
["merchant-search", throttledMerchantText],
() => getActiveMerchants(`name=${searchMerchantText}&limit=10&page=1`),
{
enabled: Boolean(throttledMerchantText),
}
);
const [searchMotherShopSlug, setSearchMotherShopSlug] = useState<string>("");
const [selectedSlug, setSelectedSlug] = useState<{
slug: string;
}>({ slug: "" });
const [throttledSlug] = useDebounce(searchMotherShopSlug, 500);
const querySlug = useQuery(
["slug-search", throttledSlug],
() =>
getMerchants(
selectedMerchant.merchant_code,
`slug=${searchMotherShopSlug}&limit=10&page=1`
),
{
enabled: Boolean(throttledSlug),
}
);
const merchantDetails = querySlug?.data?.data?.data?.shops ?? [];
const merchants = queryMerchantSearch?.data?.data?.data?.merchants ?? [];
return (
<div className="min-h-screen py-5 p-4">
<h1 className="mb-5">Create Shop</h1>
<Formik
initialValues={{
name: "",
logo_image: "",
image: "",
longitude: "",
latitude: "",
contact_number: "",
mother_shop_slug: "",
shop_type: "regular",
bin_no: "",
trade_license_no: "",
key_personnel: [
{
name: "",
designation: "",
phone_no: "",
email: "",
},
],
category_head: [
{
username: "",
},
],
}}
onSubmit={async (values, actions) => {
try {
actions.setSubmitting(true);
const reqbody: any = {
name: values.name,
longitude: values.longitude,
latitude: values.latitude,
logo_image: values.logo_image,
image: values.image,
contact_number: values.contact_number,
mother_shop_slug: selectedSlug.slug,
shop_type: values.shop_type,
bin_no: values.bin_no,
trade_license_no: values.trade_license_no,
key_personnel: values.key_personnel,
category_head: values.category_head,
};
const res = await createShop(reqbody);
if (res.status == 201) {
toast.success(res.data.message);
actions.setSubmitting(false);
await removeaSinglItem("createShop");
window.location.reload();
} else {
toast.error(res.data.message);
}
} catch (err) {
console.log(err);
actions.setSubmitting(false);
toast.error("Failed to create Shop");
}
}}
validate={(values) => {
const errors: any = {};
if (!values.name) {
errors.name = "Name is Required";
}
if (!values.address) {
errors.address = "Address is Required";
}
if (!values.latitude) {
errors.latitude = "Latitude is Required";
}
if (!values.longitude) {
errors.longitude = "Longitude is Required";
}
return errors;
}}
>
{(props: FormikProps<any>) => {
return (
<Form>
<fieldset className="border mb-2 p-4">
<legend className="px-2 ml-2 font-semibold">Shop:</legend>
<div className="flex items-center">
<div className="mb-6">
<ImageUploadCrop
title="Upload Logo"
setFieldValue={(value: string) =>
props.setFieldValue("logo_image", value)
}
logo={props.values.logo_image}
/>
</div>
<div className="ml-6 mb-6">
<ImageUploadCrop
title="Upload Cover Image"
setFieldValue={(value: string) =>
props.setFieldValue("image", value)
}
logo={props.values.image}
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"name"}>{"Name*"}</label>
<Field
type="text"
name="name"
placeholder="Name"
id={"name"}
className={"form-input"}
/>
{props.errors.name && (
<p className="text-red-500">{props.errors.name}</p>
)}
</div>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"latitude"}>{"Latitude*"}</label>
<Field
type="number"
name="latitude"
id="latitude"
className={"form-input"}
/>
{props.errors.latitude && (
<p className="text-red-500">{props.errors.latitude}</p>
)}
</div>
<div className="mb-6">
<label htmlFor={"longitude"}>{"Longitude*"}</label>
<Field
type="number"
name="longitude"
id="longitude"
className={"form-input"}
/>
{props.errors.longitude && (
<p className="text-red-500">{props.errors.longitude}</p>
)}
</div>
</div>
<div className="mb-6">
<MapViewWithSearch
lat={
props.values.latitude ? props.values.latitude : 23.777176
}
address={props.values.address}
lng={
props.values.longitude
? props.values.longitude
: 90.399452
}
onChangeAddress={(lat, lng, address) => {
props.setFieldValue("address", address);
props.setFieldValue("latitude", lat);
props.setFieldValue("longitude", lng);
}}
/>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"contact_number"}>{"Contact Number"}</label>
<Field
type="number"
name="contact_number"
id="contact_number"
className={"form-input"}
/>
</div>
<div className="mb-6">
<label htmlFor={"shop_type"}>{"Shop Type"}</label>
<Field as="select" name="shop_type" className="form-select">
<option value="regular">Regular</option>
<option value="campaign">Campaign</option>
<option value="express">Express</option>
</Field>
</div>
<div className="mb-6">
<label htmlFor={"organisation_type"}>
{"Organization Type"}
</label>
<Field
as="select"
name="organisation_type"
className="form-select"
>
<option value="small">Small</option>
<option value="medium">Medium</option>
<option value="large">Large</option>
</Field>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-4" role="group">
<p className="block mb-2">Is Delivery Hero Allowed</p>
<label className="mr-4">
<input
name="is_delivery_hero_allowed"
type="radio"
checked={!props.values.is_delivery_hero_allowed}
onChange={() => {
props.setFieldValue(
"is_delivery_hero_allowed",
false
);
}}
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_delivery_hero_allowed"
type="radio"
checked={props.values.is_delivery_hero_allowed}
onChange={() =>
props.setFieldValue(
"is_delivery_hero_allowed",
true
)
}
/>{" "}
<span className="ml-2">Yes</span>
</label>
</div>
<div className="mb-4" role="group">
<p className="block mb-2">Is Cash On Delivery Allowed</p>
<label className="mr-4">
<input
name="is_cod_allowed"
type="radio"
checked={!props.values.is_cod_allowed}
onChange={() => {
props.setFieldValue("is_cod_allowed", false);
}}
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_cod_allowed"
type="radio"
checked={props.values.is_cod_allowed}
onChange={() =>
props.setFieldValue("is_cod_allowed", true)
}
/>{" "}
<span className="ml-2">Yes</span>
</label>
</div>
</div>
</div>
</fieldset>
<fieldset className="border mb-2 p-4">
<legend className="px-2 ml-2 font-semibold">
Mother Shop:
</legend>
<div className="mb-4" role="group">
<p className="block mb-2">Is Mother Shop</p>
<label className="mr-4">
<input
name="is_mother_shop"
type="radio"
checked={!props.values.is_mother_shop}
onChange={() => {
props.setFieldValue("is_mother_shop", false);
}}
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_mother_shop"
type="radio"
checked={props.values.is_mother_shop}
onChange={() =>
props.setFieldValue("is_mother_shop", true)
}
/>{" "}
<span className="ml-2">Yes</span>
</label>
</div>
{!props.values.is_mother_shop && (
<div>
<Combobox>
<label className="relative block mb-2">
<p>Mother Shop Slug</p>
<ComboboxInput
placeholder="Search Mother Shop Slug ..."
className="form-input"
onChange={(e: any) =>
setSearchMotherShopSlug(e.target.value)
}
/>
</label>
{Array.isArray(merchantDetails) && (
<ComboboxPopover
portal={false}
className="absolute bg-white border w-auto"
css={`
z-index: 2001;
`}
>
{queryMerchantSearch.isLoading ? (
<div className="flex items-center justify-center p-4">
<Loader />
</div>
) : merchantDetails.length > 0 ? (
<ComboboxList className="bg-white shadow-md ">
{merchantDetails.map(
(motherSlug, idx: number) => {
return (
<div
key={idx}
className="p-2 hover:bg-gray-100"
>
<div className="flex items-center">
<ComboboxOption
value={motherSlug.slug}
className="w-full text-xs cursor-pointer"
onClick={() => {
setSelectedSlug({
slug: motherSlug.slug,
});
}}
>
<ComboboxOptionText /> -{" "}
<span className="capitalize font-semibold">
{motherSlug.slug}
</span>
</ComboboxOption>
</div>
</div>
);
}
)}
</ComboboxList>
) : (
<div className="flex items-center justify-center p-8">
{throttledSlug
? "No results found"
: "Type Mother Shop slug ..."}
</div>
)}
</ComboboxPopover>
)}
</Combobox>
</div>
)}
{props.values.is_mother_shop && (
<div className="mb-6">
<>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"bin_no"}>{"BIN No"}</label>
<Field
type="number"
name="bin_no"
id="bin_no"
className={"form-input"}
/>
</div>
<div className="mb-6">
<label htmlFor={"trade_license_no"}>
{"Trade License No"}
</label>
<Field
type="text"
name="trade_license_no"
id="trade_license_no"
className={"form-input"}
/>
</div>
</div>
<div className="block mb-6">
<p className="mb-2">
Key Personnel
<button
type="button"
onClick={() =>
props.setFieldValue("key_personnel", [
...props.values.key_personnel,
{
name: "",
designation: "",
phone_no: "",
email: "",
},
])
}
className="float-right ml-4 text-sm underline"
>
Add Key Personnel
</button>
</p>
{props.values.key_personnel.map(
(
kp: {
name: string;
designation: string;
phone_no: string;
email: string;
},
index: number
) => (
<div
key={index}
className="flex items-center p-4 mt-2 bg-gray-100 rounded"
>
<KeyPerson
setFieldValue={props.setFieldValue}
kps={props.values.key_personnel}
index={index}
kp={kp}
/>
</div>
)
)}
</div>
<div className="block mb-6">
<p className="mb-2">
Category Head
<button
type="button"
onClick={() =>
props.setFieldValue("category_head", [
...props.values.category_head,
{
username: "",
},
])
}
className="float-right ml-4 text-sm underline"
>
Add Category Head
</button>
</p>
{props.values.category_head.map(
(
ch: {
username: string;
},
index: number
) => (
<div
key={index}
className="flex items-center p-4 mt-2 bg-gray-100 rounded"
>
<CategoryHead
setFieldValue={props.setFieldValue}
chs={props.values.category_head}
index={index}
ch={ch}
/>
</div>
)
)}
</div>
</div>
</>
</div>
)}
</fieldset>
<Button black type="submit">
Submit
</Button>
</Form>
);
}}
</Formik>
</div>
);
}
in the current implementation I submit all the values of the form be it empty or not, but now my new API requires me to submit only the non empty fields in the form during form submit. How can I do it in this code implementation or is there any method or way provided by Formik to achieve this.
function nonEmptyObject(obj: any) {
for (const propName in obj) {
if (
obj[propName] === null ||
obj[propName] === undefined ||
obj[propName] === ""
) {
delete obj[propName];
}
}
return obj;
}
if (values.key_personnel) {
reqbody.key_personnel = values.key_personnel;
}
if (values.category_head) {
reqbody.category_head = values.category_head;
}
if (values.bdm) {
reqbody.bdm = values.bdm;
}
if (values.kam) {
reqbody.bdm = values.kam;
}
if (values.vm) {
reqbody.vm = values.vm;
}
const finalPayload = nonEmptyObject(reqbody);
const res = await createShop(finalPayload);
console.log({ finalPayload });
console.log({ res });
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.