Monday, February 17, 2025

React - AddEmployee - handleChange Function

AddEmployee component that includes a dropdown list for selecting the department instead of manually entering the deptId. This modification ensures a better user experience by allowing users to select a department from a preloaded list.

Key Changes:

  1. Fetch Departments: The component fetches the department list from an API (http://localhost:9090/api/departments).
  2. Dropdown for Department Selection: Instead of entering a department ID manually, users can select from a dropdown.
  3. Improved Error Handling: Added better error handling and logging.
import React, { useState, useEffect } from "react";
import axios from "axios";
import { Form, Button, Container, Alert } from "react-bootstrap";
import { useNavigate } from "react-router-dom";
const AddEmployee = () => {
  const [employee, setEmployee] = useState({
    empName: "",
    designation: "",
    dateOfJoining: "",
    salary: 0,
    empPhoneNumber: "",
    isActive: true,
    deptId: "",
  });
  const [departments, setDepartments] = useState([]);
  const [error, setError] = useState("");
  const navigate = useNavigate();
  const EMPLOYEE_API_URL = "http://localhost:9090/api/employees";
  const DEPARTMENT_API_URL = "http://localhost:9090/api/departments";
  // Fetch department list from API
  useEffect(() => {
    const fetchDepartments = async () => {
      try {
        const response = await axios.get(DEPARTMENT_API_URL);
        setDepartments(response.data);
      } catch (error) {
        console.error("Error fetching departments:", error);
        setError("Failed to load departments.");
      }
    };
    fetchDepartments();
  }, []);
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await axios.post(EMPLOYEE_API_URL, employee);
      if (response.status === 200 || response.status === 201) {
        navigate("/"); // Redirect to the employee list after successful addition
      }
    } catch (error) {
      setError("Error adding employee. Please try again.");
      console.error("Error adding employee:", error);
    }
  };
  const handleChange = (e) => {
    const { name, value } = e.target;
    setEmployee((prevEmployee) => ({
      ...prevEmployee,
      [name]: value,
    }));
  };
  return (
    <Container>
      <h1 className="mb-4">Add Employee</h1>
      {error && <Alert variant="danger">{error}</Alert>}
      <Form onSubmit={handleSubmit}>
        <Form.Group className="mb-3">
          <Form.Label>Name</Form.Label>
          <Form.Control
            type="text"
            name="empName"
            value={employee.empName}
            onChange={handleChange}
            required
          />
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>Designation</Form.Label>
          <Form.Control
            type="text"
            name="designation"
            value={employee.designation}
            onChange={handleChange}
            required
          />
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>Date of Joining</Form.Label>
          <Form.Control
            type="date"
            name="dateOfJoining"
            value={employee.dateOfJoining}
            onChange={handleChange}
            required
          />
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>Salary</Form.Label>
          <Form.Control
            type="number"
            name="salary"
            value={employee.salary}
            onChange={handleChange}
            required
          />
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>Phone Number</Form.Label>
          <Form.Control
            type="text"
            name="empPhoneNumber"
            value={employee.empPhoneNumber}
            onChange={handleChange}
            required
          />
        </Form.Group>
        {/* Department Dropdown */}
        <Form.Group className="mb-3">
          <Form.Label>Department</Form.Label>
          <Form.Select
            name="deptId"
            value={employee.deptId}
            onChange={handleChange}
            required
          >
            <option value="">Select Department</option>
            {departments.map((dept) => (
              <option key={dept.deptId} value={dept.deptId}>
                {dept.deptName}
              </option>
            ))}
          </Form.Select>
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Check
            type="checkbox"
            name="isActive"
            label="Is Active"
            checked={employee.isActive}
            onChange={(e) =>
              setEmployee({ ...employee, isActive: e.target.checked })
            }
          />
        </Form.Group>
        <Button variant="primary" type="submit">
          Add Employee
        </Button>
      </Form>
    </Container>
  );
};
export default AddEmployee;


Explanation of the handleChange Function

This function is used to update the state of the employee object dynamically whenever an input field changes. It ensures that all form fields update their respective values without overwriting the existing state.


Breakdown of the Code:


const handleChange = (e) => { const { name, value } = e.target; setEmployee((prevEmployee) => ({ ...prevEmployee, [name]: value, })); };

Step-by-Step Explanation:

  1. Extract the name and value from the input field (e.target)


    const { name, value } = e.target;
    • e.target refers to the input field that triggered the onChange event.
    • name corresponds to the name attribute of the input field (e.g., "empName""designation", etc.).
    • value is the current value entered in the input field.
  2. Update the employee state using setEmployee


    setEmployee((prevEmployee) => ({ ...prevEmployee, [name]: value, }));
    • The function takes the previous state (prevEmployee) and creates a new state object.
    • The spread operator (...prevEmployee) ensures that all existing properties of the employee object remain unchanged.
    • [name]: value dynamically updates the specific field that changed, using the name extracted from e.target.

Example of How It Works

Initial State (employee object):


{ empName: "", designation: "", dateOfJoining: "", salary: 0, empPhoneNumber: "", isActive: true, deptId: "", }

Scenario: User Types "John Doe" in the Name Field


<input type="text" name="empName" value={employee.empName} onChange={handleChange} />
  • The name of this field is "empName", and when the user types "John Doe", the value is "John Doe".
  • The function updates the state:

    setEmployee((prevEmployee) => ({ ...prevEmployee, empName: "John Doe", }));
  • Now, the updated state:

    { empName: "John Doe", designation: "", dateOfJoining: "", salary: 0, empPhoneNumber: "", isActive: true, deptId: "", }

Scenario: User Selects a Department from the Dropdown


<select name="deptId" value={employee.deptId} onChange={handleChange}> <option value="1">HR</option> <option value="2">IT</option> </select>
  • Suppose the user selects the IT department, which has a deptId of "2".
  • The function updates the state:

    setEmployee((prevEmployee) => ({ ...prevEmployee, deptId: "2", }));
  • Updated state:

    { empName: "John Doe", designation: "", dateOfJoining: "", salary: 0, empPhoneNumber: "", isActive: true, deptId: "2", }

Key Benefits of This Approach

✅ Dynamic Field Updates: Works for all input fields (text, date, number, dropdowns) without writing separate handlers.
✅ Prevents Overwriting: The spread operator (...prevEmployee) ensures only the modified field updates while keeping the other fields intact.
✅ Reusability: The function is generic and can be used for any form input field with a name attribute.

This pattern is a best practice in React for handling form state efficiently!

No comments:

Post a Comment