2

I'm using react-hook-form to valid fields before submitting my form. However, I'm trying to change one input to be react-number-format, but it is not using the same input style and it's not working for the register error validation.

import React, { useState } from 'react';
import { Controller, useForm } from "react-hook-form";
import {
    Form,
    Label,
    Input,
    Button
} from 'reactstrap';
import { FormGroup } from '@material-ui/core';
import moment from 'moment';
import DatePicker from "reactstrap-date-picker";
import NumberFormat from 'react-number-format';

const setErrorStyle = (name) => {
    return { 
        borderColor: name ? 'red' : '', 
        boxShadow: name ? '0 0 1.5px 1px red' : '' 
    }
}

const Test = () => {
    const [ addBill, setAddBill ] = useState({
        debitAmt: '',
        invoiceNumber: '',
        memo: '',
        invoiceDate: moment().format('YYYY-MM-DD'),
    });
    
    const { register, handleSubmit, errors, control } = useForm();

    const submitAddBill = (data) => {
        console.log(data);
    }

    return (
        <>
            <Form onSubmit={handleSubmit(submitAddBill)}>
                <div className="row">
                    <div className="col-sm-2">
                        <FormGroup className="mr-10 mb-10">
                            <Label for="debitAmt" className="mr-sm-10">Debit Amt</Label>
                            <Controller
                                as={
                                    <NumberFormat
                                        thousandSeparator={true}
                                        prefix={"$"}
                                        onValueChange={(v) => {
                                            setAddBill({...addBill, debitAmt: v.floatValue === undefined ? '' : v.floatValue})
                                        }}
                                    />
                                }
                                name="debitAmt"
                                id="debitAmt"
                                variant="outlined"
                                defaultValue={addBill.debitAmt}
                                innerRef={register({ required: true })} aria-invalid={errors.debitAmt ? "true" : "false"}
                                control={control}
                                style={setErrorStyle(errors.debitAmt)}
                            />
                            {errors.debitAmt && (
                                <span style={{ color: "red" }} role="alert">required</span>
                            )}
                        </FormGroup>
                    </div>
                    <div className="col-sm-2">
                        <FormGroup className="mr-10 mb-10">
                            <Label for="invoiceDate" className="mr-sm-10">Invoice Date</Label>
                            <DatePicker name="invoiceDate" id="invoiceDate"
                                value={addBill.invoiceDate} onChange={(e) => setAddBill({...addBill, invoiceDate: e ? moment(e).format('YYYY-MM-DD') : ''})}
                                innerRef={register({ required: true })} aria-invalid={errors.invoiceDate ? "true" : "false"}
                                style={setErrorStyle(errors.invoiceDate)}
                            />
                            {errors.invoiceDate && (
                                <span style={{ color: "red" }} role="alert">required</span>
                            )}
                        </FormGroup>
                    </div>
                    <div className="col-sm-3">
                        <FormGroup className="mr-10 mb-10">
                            <Label for="invoiceNumber" className="mr-sm-10">Invoice Number</Label>
                            <Input type="text" name="invoiceNumber" id="invoiceNumber" placeholder="1234567" 
                                innerRef={register({ required: true })} aria-invalid={errors.invoiceNumber ? "true" : "false"}
                                value={addBill.invoiceNumber} onChange={(e) => setAddBill({...addBill, invoiceNumber: e.target.value})}
                                style={setErrorStyle(errors.invoiceNumber)}
                            />
                            {errors.invoiceNumber && (
                                <span style={{ color: "red" }} role="alert">required</span>
                            )}
                        </FormGroup>
                    </div>
                    <div className="col-sm-3">
                        <FormGroup className="mr-10 mb-10">
                            <Label for="memo" className="mr-sm-10">Memo</Label>
                            <Input type="text" name="memo" id="memo" placeholder="Memo" 
                                innerRef={register()} aria-invalid={errors.memo ? "true" : "false"}
                                value={addBill.memo} onChange={(e) => setAddBill({...addBill, memo: e.target.value})}
                                style={setErrorStyle(errors.memo)}
                            />
                        </FormGroup>
                    </div>
                </div>
                <Button type="submit" color="primary" size="sm" className="w-auto">Add Bill</Button>
            </Form>
        </>
    )
}

export default Test;

Also, when I submit the form and check the log, the debitAmt data is not there.

Thanks

2

1 Answer 1

1

The prop innerRef doesn't exist on NumberFormat component instead use getInputRef prop on NumberFormat

Example Implementation

<FormGroup className="mr-10 mb-10">
          <Label for="debitAmt" className="mr-sm-10">
            Debit Amt
          </Label>
          <Controller
            as={
              <NumberFormat
                thousandSeparator={true}
                prefix={"$"}
                onValueChange={(v) => {
                  setAddBill({
                    ...addBill,
                    debitAmt: v.floatValue === undefined ? "" : v.floatValue
                  });
                }}
              />
            }
            name="debitAmt"
            id="debitAmt"
            variant="outlined"
            defaultValue={addBill.debitAmt}
            getInputRef={register({ required: true })}
            aria-invalid={errors.debitAmt ? "true" : "false"}
            control={control}
            style={setErrorStyle(errors.debitAmt)}
          />
          {errors.debitAmt && (
            <span style={{ color: "red" }} role="alert">
              required
            </span>
          )}
        </FormGroup>

Example Sandbox here

Sign up to request clarification or add additional context in comments.

4 Comments

Perfect! Thank you.
An odd behavior is that when I update the state of addBill.debitAmt in another part of the code that is not the onValueChange of NumberFormat, it doesn't update in the field. Why?
@myTest532myTest532 You have to make the NumberFormat controllable to that the value will be up to date with state
Could you please give me an example of it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.