SoftTimur
SoftTimur

Reputation: 5520

How to remove empty error div from DOM in formik form?

I have the following code in the authentication page to control alert messages:

<div className="messages-wrapper">
  {formik.errors.email &&
    <div className="alert alert-danger">
      <ErrorMessage name="email" />
    </div>
  }
  {formik.errors.password &&
    <div className="alert alert-danger">
      <ErrorMessage name="password" />
    </div>
  }
  {error && <div className="alert alert-danger">{error}</div>}
</div>

I realize that sometimes in DOM it has:

<div class="alert alert-danger"></div>

As a consequence, there is a pink bar in the display.

Does anyone know how to implement such that we only display an alert bar when it has text?

enter image description here

Upvotes: 3

Views: 1096

Answers (5)

Ajeet Shah
Ajeet Shah

Reputation: 19843

All you need to do is make use of touched property of FormikState:

export interface FormikState<Values> {
    values: Values;
    errors: FormikErrors<Values>;
    touched: FormikTouched<Values>;   // <=== This one
    isSubmitting: boolean;
    isValidating: boolean;
    status?: any;
    submitCount: number;
}

Here is how to get access to touched state for form:

<Formik
  initialValues={{ email: '', password: '' } as IForm}
  validate={(values) => {
    const errors = {} as IForm
    if (!values.email) {
      errors.email = 'Email Required'
    }
    return errors
  }}
  onSubmit={(values, { setSubmitting }) => {
    // ... submit handler
  }}
>
  {({ values, errors, touched, handleChange, handleBlur, handleSubmit, 
isSubmitting }) => (
                //  above ^ one
    <form onSubmit={handleSubmit}>
    // ... ...

And then use it when showing errors (note the usage of touched.email and touched.password):

<div className="messages-wrapper">
  {errors.email && touched.email && (
    <div className="alert alert-danger">
      <ErrorMessage name="email" />
    </div>
  )}

  {errors.password && touched.password && (
    <div className="alert alert-danger">
      <ErrorMessage name="password" />
    </div>
  )}
</div>

To see all of it (Problem + Solution) in action: Playground


Snapshot: No empty div in DOM inside wrapper:

no empty dom

Upvotes: 1

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85575

Without going deeper, I would simply fix by applying css:

.alert:empty {
  display: none;
}

Otherwise, I would trim value before its check. Eg.

{formik.errors.email.trim() &&

Upvotes: -1

x00
x00

Reputation: 13843

The code sample you've provided is not enough to give you a definitive answer.

But from what I see I can figure this much:

  1. As per documentation 1 and 2 and the source code the <ErrorMessage name="email"> will returns a string, and you code is roughly equivalent to
    {formik.errors.email && <div className="alert alert-danger">
      {formik.touched.email && formik.errors.email ? formik.errors.email : null}
    </div>}
    
  2. Now I see two possibilities for an empty error bar to appear:

    1. formik.errors.email must be truthy, but not printable (like for example " ").
    2. formik.errors.email must be truthy, and formik.touched.email must be falsy.

    Most probably it's the second issue you're experiencing.

So, if I guessed right, you need to either:

  1. Use ErrorMessage as it is recommended in the docs. Like so:
    <ErrorMessage name="email">
      {msg => <div className="alert alert-danger">{msg}</div>}
    </ErrorMessage>
    
    Or like so:
    <ErrorMessage
      name="email"
      render={msg => <div className="alert alert-danger">{msg}</div>}
    />
    
  2. Or get rid of <ErrorMessage>, but add a check for the touched
    {formik.touched.email && formik.errors.email &&
      <div className="alert alert-danger">{formik.errors.email}</div>
    }
    

Upvotes: 1

Shubham Khatri
Shubham Khatri

Reputation: 281864

The reason You see the pink bar is because when you have an error with your form submission you render an error message.

Since you use bootstrap classes such as alert alert-danger on the alert message, the alert is styled as per bootstrap(assuming youare using bootstrap)

According to bootstrap documentation:

Use the .alert-${link} utility class to quickly provide matching colored links within any alert.

And accordingly

alert-success - leaves a green color background
alert-info - shows a blue color background
alert-waning- shows a yellow color background
alert-danger - shows a pink/red color background

In order for you to remove the pink styling, you can just remove alert-dangerclass from the alert message

{error && <div className="alert">{error}</div>}

Now this will inherit the styles of alert class and if you don't want it, you can just add your custom class and apply styles on it

You code might look like

<div className="messages-wrapper">
      {formik.errors.email && <div className="alert">
        <ErrorMessage name="email" />
      </div>
      }
      {formik.errors.password && <div className="alert">
        <ErrorMessage name="password" />
      </div>
      }
      {error && <div className="alert">{error}</div>}
    </div>

Upvotes: 0

gdh
gdh

Reputation: 13692

Make sure to initialise all input/field values (may be you have forgotten to initialise value for email?

I have tried to replicate your issue and I was able to see empty pink bar when I don't initialise any field value.

  ...
<Formik
      initialValues={{ email: "", password: "" }} // <---- correct - both email and password are initialised
      // initialValues={{ password: "" }} // <--- wrong, email is not initialised. With this, there will be empty pink bar issue
      validate={validate}
      onSubmit={(values, actions) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }, 1000);
      }}
  ...

See this example I created in codesandbox if it is useful

Lastly, I am not sure why do you have the line of code {error && <div className="alert alert-danger">{error}</div>}. Just check on that as well. Good luck.

Upvotes: 1

Related Questions