I created a custom QRcode reader that added as button to formik customTextInout.tsx
but when I click on it, it will submit with no value in it.
in this code I created a button that when you click on it, it will show the QrCodeReader.
QrReaderButton.tsx
import { useState } from "react";
import { QrReader } from "react-qr-reader";
import qrcode from "../assets/qr-code.png";
interface Props {
setQrData: any;
}
const QrReaderButton: React.FC<Props> = (props) => {
const [data, setData] = useState<any>();
const [show, setShow] = useState<boolean>(false);
let a;
return (
<div className="flex flex-col w-max items-center">
<button
type="button"
onClick={() => (!show ? setShow(true) : setShow(false))}
>
<img src={qrcode} alt="qr-code" width={40} />
</button>
{show && (
<div className="w-96">
<QrReader
onResult={(result: any, error) => {
if (!!result) {
setData(JSON.parse(result?.text));
props.setQrData(JSON.parse(result?.text));
}
if (!!error) {
// console.info(error);
}
}}
constraints={{ facingMode: "user" }}
/>
<p> {data ? JSON.stringify(data) : "No result"}</p>
</div>
)}
</div>
);
};
export default QrReaderButton;
in this code I created a custom input for formik with help of formik official docs CustomTextInput.tsx
import {
FormControl,
FormHelperText,
FormLabel,
Input,
} from "@chakra-ui/react";
import QrReaderButton from "../QrReaderButton";
const CustomTextInput = ({
field,
form: { touched, errors },
...props
}: any) => {
return (
<FormControl isInvalid={errors.name && touched.name}>
<FormLabel>{props.label}</FormLabel>
<div className="flex gap-2">
<Input {...field} {...props} />
<div className="w-max">
<QrReaderButton
setQrData={() => {
console.log("test");
}}
/>
</div>
</div>
<FormHelperText>this is helper</FormHelperText>
</FormControl>
);
};
export default CustomTextInput;
in this code I used CustomTextInout component with chakra-ui modal.
FormModal.tsx
import {
useDisclosure,
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
FormLabel,
useToast,
ModalFooter,
} from "@chakra-ui/react";
import { Formik, Form, Field } from "formik";
import { useNavigate } from "react-router-dom";
import CustomNumberInput from "./CustomInputs/CustomNumberInput";
import CustomOptionInput from "./CustomInputs/CustomOptionInput";
import CustomTextInput from "./CustomInputs/CustomTextInput";
import TokenButton from "./TokenButton";
interface Props {
key: string;
Title: string;
buttonValue?: string;
image: string;
nav: string;
initialValues: any;
isLoading: boolean;
apiHook: any;
validateName: any;
}
const FormModal: React.FC<Props> = (props) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate();
const toast = useToast();
return (
<div className="w-full content-center ">
<TokenButton
nav={props.nav}
image={props.image}
title={props.Title}
onClick={onOpen}
/>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>{props.Title}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Formik
initialValues={props.initialValues}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
props
.apiHook(values)
.unwrap()
.catch((e: any) => {
// alert(JSON.stringify(e, null, 2))
toast({
status: "error",
title: "Error",
description: JSON.stringify(e, null, 2),
isClosable: true,
});
if (e.status == 401) {
setTimeout(() => {
navigate("/login");
}, 1000);
localStorage.clear();
}
});
}}
>
{(propsForm) => (
<Form
onSubmit={propsForm.handleSubmit}
onReset={propsForm.handleReset}
className="w-full h-full bg-[#ced8d7ac] shadow-2xl rounded-2xl p-4 items-center content-center text-current"
>
<FormLabel>{props.Title}</FormLabel>
<div className="grid lg:grid-cols-1 md:grid-cols-2 gap-4">
{Object.keys(props.initialValues).map((key) => {
return (
<Field
id={key}
key={key}
name={key}
label={key}
backgroundColor="#ffffffe1"
component={CustomTextInput}
/>
);
})}
</div>
<Button
type="submit"
isLoading={props.isLoading}
className="gre mt-2"
>
{props.Title}
</Button>
</Form>
)}
</Formik>
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Close
</Button>
<Button variant="ghost">{props.buttonValue}</Button>
</ModalFooter>
</ModalContent>
</Modal>
</div>
);
};
export default FormModal;
CodePudding user response:
Default behavior of button in form is submit. so you need to make sure that you specified a type except the submit.
See reference in here
Your code will be like below
QrReaderButton
import { useState } from "react";
import { QrReader } from "react-qr-reader";
import qrcode from "../assets/qr-code.png";
interface Props {
setQrData: any;
}
const QrReaderButton: React.FC<Props> = (props) => {
const [data, setData] = useState<any>();
const [show, setShow] = useState<boolean>(false);
let a;
return (
<div className="flex flex-col w-max items-center">
<button
type="button" //make sure you add this
onClick={() => (!show ? setShow(true) : setShow(false))}
>
<img src={qrcode} alt="qr-code" width={40} />
</button>
{show && (
<div className="w-96">
<QrReader
onResult={(result: any, error) => {
if (!!result) {
setData(JSON.parse(result?.text));
props.setQrData(JSON.parse(result?.text));
}
if (!!error) {
// console.info(error);
}
}}
constraints={{ facingMode: "user" }}
/>
<p> {data ? JSON.stringify(data) : "No result"}</p>
</div>
)}
</div>
);
};
export default QrReaderButton;