Search code examples
reactjsformssubmitcrudfunc

How prevent submit edit form when anything is not changed?


I have a form like this that I created with context crud project. Here I want that if no changes have been made in the form, it should not be updated and a notification should be issued. How can I do this? Note: also, if any input is empty, do not submit. How can I do this without required the input. How can I fix these problems?

import React from "react";
import { NavLink } from "react-router-dom";
import { useContext, useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { GlobalContext } from "../../context/GlobalState";
import styles from "../ContactForm/Form.module.scss";
import { toast } from "react-toastify";
const EditContactForm = () => {
  const { contacts, UPDATE_CONTACT } = useContext(GlobalContext);

  const [selectedContact, setSelectedContact] = useState({
    id: "",
    name: "",
    surname: "",
    fatherName: "",
    specialty: "",
    email: "",
    gender: "",
    test:''
  });
  const history = useNavigate();

  const { id } = useParams();

  useEffect(() => {
    const userId = id;
    const selectedContact = contacts.find((user) => String(user.id) === userId);
    if (selectedContact) {
      setSelectedContact(selectedContact);
    }
  }, [id, contacts]);

  function onSubmit(e) {
    e.preventDefault();
    if(selectedContact){
    UPDATE_CONTACT(selectedContact);
    console.log("new user edited:", selectedContact);
    history("/contacts");
    toast('updated')
    }
    else if(selectedContact===contacts){
      toast('anything doesnt changed') // problem is there
    }
  }

  const handleOnChange = (e) => {
    setSelectedContact((selectedContact) => ({
      ...selectedContact,
      [e.target.name]: e.target.value,
    }));
  };

  const inputHandleChange = (e) => {
    setSelectedContact({
      ...selectedContact,
      [e.target.name]: e.target.checked ? e.target.id : "",
    });
  };

  const selectOptions = [
    { label: "One", value: 1 },
    { label: "Two", value: 2 },
    { label: "Three", value: 3 },
  ];
  const onChange = (e) => setSelectedContact({ ...selectedContact, [e.target.name]: e.target.value })
  return (
    <div className={styles.form}>
      <form onSubmit={onSubmit}>
        <div class="mb-3 row row d-flex justify-content-around">
          <label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Name</label>
          <div class="col-sm-8">
            <input
              class="form-control"
              name="name"
              required
              value={selectedContact?.name ?? ""}
              onChange={handleOnChange}
            />
          </div>
        </div>

        <div class="mb-3 row row d-flex justify-content-around">
          <label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Surname</label>
          <div class="col-sm-8">
            <input
              class="form-control"
              name="surname"
              required
              value={selectedContact?.surname ?? ""}
              onChange={handleOnChange}
            />
          </div>
        </div>

        <div class="mb-3 row row d-flex justify-content-around">
          <label className={`col-sm-2 p-0 ${styles.inputLabel}`}>
            Father Name
          </label>
          <div class="col-sm-8">
            <input
              class="form-control"
              name="fatherName"
              required
              value={selectedContact?.fatherName ?? ""}
              onChange={handleOnChange}
            />
          </div>
        </div>

        <div class="mb-3 row row d-flex justify-content-around">
          <label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Email</label>
          <div class="col-sm-8">
            <input
              class="form-control"
              name="email"
              required
              value={selectedContact?.email ?? ""}
              onChange={handleOnChange}
            />
          </div>
        </div>

        <div class="mb-3 row row d-flex justify-content-around">
          <label className={`col-sm-2 p-0 ${styles.inputLabel}`}>
            Specialty
          </label>
          <div class="col-sm-8">
            <input
              class="form-control"
              name="specialty"
              required
              value={selectedContact?.specialty ?? ""}
              onChange={handleOnChange}
            />
          </div>
        </div>

        <div className="mb-3 row row d-flex justify-content-around">
          <label className={`col-sm-2 p-0 ${styles.inputLabel}`}>position</label>
          <div className="col-sm-8 d-flex justify-content-center align-items-center">
          <select
            onChange={onChange}
            value={selectedContact.test}
            name="test"
            class="form-select"
            aria-label="Default select example"
          >
            {selectOptions.map((item) => (
              <option 
              key={item.value} 
              value={item.value}
              >
              {item.label}
              </option>
            ))}
          </select>
          </div>
        </div>

        <div className="mb-3 row row d-flex justify-content-around">
          <label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Gender</label>
          <div className="col-sm-8">
            <div class="form-check form-check-inline ">
              <input
                class="form-check-input"
                type="radio"
                name="gender"
                id="male"
                checked={selectedContact.gender === "male"}
                onChange={inputHandleChange}
              />
              <label class="form-check-label">Male</label>
            </div>
            <div class="form-check form-check-inline">
              <input
                class="form-check-input"
                type="radio"
                name="gender"
                id="female"
                checked={selectedContact.gender === "female"}
                onChange={inputHandleChange}
              />
              <label class="form-check-label">Female</label>
            </div>
          </div>
        </div>

        <div className="mb-3 row d-flex justify-content-around">
          <div class="form-check col-sm-11">
            <input
              class="form-check-input"
              type="checkbox"
              name="updatesNotification"
              id="update"
              checked={selectedContact.updatesNotification === "update"}
              onChange={(e) =>
                setSelectedContact({
                  ...selectedContact,
                  [e.target.name]: e.target.checked ? e.target.id : "",
                })
              }
            />
            <label class="form-check-label" for="flexCheckDefault">
              I want to be notified of updates
            </label>
          </div>
        </div>

        <div className={styles.buttons}>
          <button type="submit" class="btn btn-primary">
            Update a contact
          </button>
          <NavLink to="/contacts" className="btn btn-danger m-2">
            Cancel
          </NavLink>
        </div>
      </form>
    </div>
  );
};

export default EditContactForm;

import React, { useState } from "react";
import { useContext } from "react";
import { GlobalContext } from "../../context/GlobalState";
import { useNavigate } from "react-router-dom";
import { NavLink } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import styles from "../ContactForm/Form.module.scss";
import { toast } from "react-toastify";
import { Checkbox, Button, Form, Input, Select, Radio } from "antd";

const Form1 = () => {
  const { ADD_CONTACT } = useContext(GlobalContext);
  const [contact, setContact] = useState({
    id: uuidv4(),
    name: "",
    surname: "",
    fatherName: "",
    specialty: "",
    email: "",
    gender: "",
    updatesNotification: "",
    test: "",
  });

  const { Option } = Select;

  const { name, surname, fatherName, specialty, email } = contact;

  let history = useNavigate();

  const onSubmit = () => {
    if (contact) {
      ADD_CONTACT(contact);
      history("/contacts");
      console.log(contact);
      toast.success("Contact successfully added");
    }
     else{
       ???
    }

  };

  const selectOptions = [
    { label: "One", value: 1 },
    { label: "Two", value: 2 },
    { label: "Three", value: 3 },
  ];

  return (
    <>
      <Form
        onFinish={onSubmit}
        className={styles.form}
        name="myForm"
        initialValues={{
          remember: true,
        }}
        autoComplete="off"
        labelCol={{
          span: 2,
        }}
        wrapperCol={{
          span: 16,
        }}
      >
        <div className="row">
          <Form.Item
            label="Name"
            rules={[{ required: true, message: "Please input your name!" }]}
          >
            <Input
              placeholder="Enter Your Name"
              value={name}
              name="name"
              onChange={(e) =>
                setContact({ ...contact, [e.target.name]: e.target.value })
              }
            />
          </Form.Item>
        </div>

        <Form.Item
          label="Surname"
          rules={[{ required: true, message: "Please input your surname!" }]}
        >
          <Input
            placeholder="Enter Your Surname"
            value={surname}
            name="surname"
            onChange={(e) =>
              setContact({ ...contact, [e.target.name]: e.target.value })
            }
          />
        </Form.Item>

        <Form.Item
          label="Father Name"
          rules={[{ required: true, message: "Please input your surname!" }]}
        >
          <Input
            placeholder="Enter Your FatherName"
            value={fatherName}
            name="fatherName"
            onChange={(e) =>
              setContact({ ...contact, [e.target.name]: e.target.value })
            }
          />
        </Form.Item>

        <Form.Item
          label="Email"
          rules={[{ required: true, message: "Please input your mail!" }]}
        >
          <Input
            name="email"
            placeholder="your mail"
            value={email}
            onChange={(e) =>
              setContact({ ...contact, [e.target.name]: e.target.value })
            }
          />
        </Form.Item>

        <Form.Item
          label="Specialty"
          rules={[{ required: true, message: "Please input your specialty!" }]}
        >
          <Input
            name="specialty"
            placeholder="your specialt"
            value={specialty}
            onChange={(e) =>
              setContact({ ...contact, [e.target.name]: e.target.value })
            }
          />
        </Form.Item>

        <Form.Item label='Category'>
          <Select
            onChange={(e)=>setContact({ ...contact, test : e })}
            defaultValue='category'
            // value={contact.test}
            name="test"
            style={{
              width: 120,
            }}
          >
            {selectOptions.map((item) => (
              <Option key={item.value} value={item.value}></Option>
            ))}
          </Select>
        </Form.Item>

        <Form.Item label="Gender">
          <Radio.Group
            onChange={(e) =>
              setContact({
                ...contact,
                [e.target.name]: e.target.checked ? e.target.id : "",
              })
            }
            name="gender"
            rules={[{ required: true, message: "Please  your gender!" }]}
          >
            <Radio
              id="female"
              value="Female"
              checked={contact.gender === "female"}
            >
              Female
            </Radio>
            <Radio id="male" value="Male" checked={contact.gender === "male"}>
              Male
            </Radio>
          </Radio.Group>
        </Form.Item>

        <Form.Item>
          <Checkbox
            name="updatesNotification"
            checked={contact.updatesNotification === "update"}
            id="update"
            onChange={(e) =>
              setContact({
                ...contact,
                [e.target.name]: e.target.checked ? e.target.id : "",
              })
            }
          >
            I want to be notified of updates
          </Checkbox>
        </Form.Item>

        <div className={styles.buttons}>
          <Button type="primary" htmlType="submit">
            Add contact
          </Button>
          <NavLink to="/contacts">
            <Button danger>Cancel</Button>
          </NavLink>
        </div>
      </Form>
    </>
  );
};

export default Form1;
enter image description here


Solution

  • One way to check if two objects are equal is to transform them into string.

    JSON.stringify(selectedContact) === JSON.stringify(contacts.find((user) => user.id === selectedContact.id))
    

    For checking if one if the data is empty one way is using the method some, this method send true if one the item in an array match the condition.

        if (Object.keys(selectedContact).some(key => !selectedContact[key])) {
        alert('There are missing information')
    }