Home > Enterprise >  Formik QRcodeReader button submit for itself
Formik QRcodeReader button submit for itself

Time:12-11

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;
  • Related