0

onChange dosent get triggered on first change for filter function filterFn, the changeDepartmentIdFilter function dosent change the value of departmentIdFilter on first change example

if i write

apple

it consoles only

appl

here is the code :

const Department = () => {


    let [department, setDepartment] = useState([])
    let [filteredDepartment, setFilteredDepartment] = useState([])
    
    let [values, setValues] = useState({
        modalTitle: '',
        departmentName: '',
        departmentId: 0,

        departmentIdFilter: "",
        departmentNameFilter: "",
        departmentsWithoutFilter: [],
    })

    useEffect (() => {
        getDepartments()
    }, [])


    let filterFn = () =>{
        let departmentIdFilter = values.departmentIdFilter
        let departmentNameFilter = values.departmentNameFilter


        let filteredData = filteredDepartment.filter(
            function(el){
                return el.DepartmentId.toString().toLowerCase().includes(
                    departmentIdFilter.toString().trim().toLowerCase()
                ) &&
                el.DepartmentName.toString().toLowerCase().includes(
                    departmentNameFilter.toString().trim().toLowerCase()
                )

            }
        )
        setDepartment(filteredData)

    }


    let changeDepartmentIdFilter = (e) => {
        setValues({...values, 'departmentIdFilter': e.target.value})
        filterFn()
    }
    
    
    let changeDepartmentNameFilter = (e) => {
        console.log(e.target.value)
        setValues({...values, 'departmentNameFilter': e.target.value})
        filterFn()
    }


    let getDepartments = async () => {
        let response = await fetch (variables.API_URL + "department")
        let data = await response.json()

        setDepartment(data)
        setFilteredDepartment(data)
    }

  
    return (
        <div>

            <button type="button" className="btn btn-primary m-2 float-end" data-bs-toggle="modal" data-bs-target="#exampleModal" onClick={() => addClick()}>Add Department</button>

            <table className="table table-striped">
                <thead>
                    <tr>
                        <th>
                            <input className="form-control m-2" onChange={(e) => {changeDepartmentIdFilter(e)}} placeholder='Filter' />
                            DepartmentId
                        </th>
                        <th>
                            <input className="form-control m-2" onChange={(e) => {changeDepartmentNameFilter(e)}} placeholder='Filter' />
                            DepartmentName
                        </th>
                        <th>
                            Options
                        </th>
                    </tr>
                </thead>
                <tbody>
                    {department.map((dep) => 

                        <tr key={dep.DepartmentId}>
                            <td>{dep.DepartmentId}</td>
                            <td>{dep.DepartmentName}</td>
                            <td>
                                

                                <button type="button" className="btn btn-light mr-1" data-bs-toggle="modal" data-bs-target="#exampleModal" onClick={() => editClick(dep)}>
                                    
                                </button>


                                <button type="button" className="btn btn-light mr-1" onClick={() => deleteClick(dep.DepartmentId)}>
                                    
                                </button>

                            </td>
                        </tr>
                        )}
                </tbody>
            </table>

            <div className="modal fade" id="exampleModal" tabIndex="-1" aria-hidden="true">
                <div className="modal-dialog modal-lg modal-dialog-centered">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h5 className="modal-title">{values.modalTitle}</h5>

                            <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close">
                            </button>

                        </div>

                        <div className="modal-body">
                            <div className="input-group mb-3">
                                <span className="input-group-text">Department Name</span>
                                <input name = 'departmentName' type="text" className="form-control" value={values.departmentName} onChange={(e) => {changeDepartmentName(e)}} />
                                {/* <input type="text" className="form-control" value={departmentName} onChange={changeDepartmentName} /> */}
                            </div>

                            {values.departmentId == 0 ?
                                <button type="button" className="btn btn-primary float-start" onClick={() => createClick()}>Create</button> :
                                null
                            }

                            {values.departmentId != 0 ?
                                <button type="button" className="btn btn-primary float-start" onClick={() => updateClick()}>Edit</button> :
                                null
                            }

                        </div>

                    </div>
                </div>
            </div>

        </div>
    )
}

export default Department

Reduced Code with only relevant code:

const Department = () => {


let [department, setDepartment] = useState([])
let [filteredDepartment, setFilteredDepartment] = useState([])

let [values, setValues] = useState({
    modalTitle: '',
    departmentName: '',
    departmentId: 0,

    departmentIdFilter: "",
    departmentNameFilter: "",
    departmentsWithoutFilter: [],
})

useEffect (() => {
    getDepartments()
}, [])


let filterFn = () =>{
    let departmentIdFilter = values.departmentIdFilter
    let departmentNameFilter = values.departmentNameFilter


    let filteredData = filteredDepartment.filter(
        function(el){
            return el.DepartmentId.toString().toLowerCase().includes(
                departmentIdFilter.toString().trim().toLowerCase()
            ) &&
            el.DepartmentName.toString().toLowerCase().includes(
                departmentNameFilter.toString().trim().toLowerCase()
            )

        }
    )
    setDepartment(filteredData)

}


let changeDepartmentIdFilter = (e) => {
    setValues({...values, 'departmentIdFilter': e.target.value})
    filterFn()
}


let changeDepartmentNameFilter = (e) => {
    console.log(e.target.value)
    setValues({...values, 'departmentNameFilter': e.target.value})
    filterFn()
}


 return (
        <div>

            <button type="button" className="btn btn-primary m-2 float-end" data-bs-toggle="modal" data-bs-target="#exampleModal" onClick={() => addClick()}>Add Department</button>

            <table className="table table-striped">
                <thead>
                    <tr>
                        <th>
                            <input className="form-control m-2" onChange={(e) => {changeDepartmentIdFilter(e)}} placeholder='Filter' />
                            DepartmentId
                        </th>
                        <th>
                            <input className="form-control m-2" onChange={(e) => {changeDepartmentNameFilter(e)}} placeholder='Filter' />
                            DepartmentName
                        </th>
                        <th>
                            Options
                        </th>
                    </tr>
                </thead>
                <tbody>
                    {department.map((dep) => 

                        <tr key={dep.DepartmentId}>
                            <td>{dep.DepartmentId}</td>
                            <td>{dep.DepartmentName}</td>
                            <td>
                                
                                {/* >>>>>>EDIT BUTTON<<<<<< */}
                                <button type="button" className="btn btn-light mr-1" data-bs-toggle="modal" data-bs-target="#exampleModal" onClick={() => editClick(dep)}>
                                </button>

                                {/* >>>>>>>DELETE BUTTON<<<<<<<<<<< */}
                                <button type="button" className="btn btn-light mr-1" onClick={() => deleteClick(dep.DepartmentId)}>
                                </button>

                            </td>
                        </tr>
                        )}
                </tbody>
            </table>

            <div className="modal fade" id="exampleModal" tabIndex="-1" aria-hidden="true">
                <div className="modal-dialog modal-lg modal-dialog-centered">
                    <div className="modal-content">
                        <div className="modal-header">
                            <h5 className="modal-title">{values.modalTitle}</h5>

                            <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close">
                            </button>

                        </div>

                        <div className="modal-body">
                            <div className="input-group mb-3">
                                <span className="input-group-text">Department Name</span>
                                <input name = 'departmentName' type="text" className="form-control" value={values.departmentName} onChange={(e) => {changeDepartmentName(e)}} />
                            </div>

                            {values.departmentId == 0 ?
                                <button type="button" className="btn btn-primary float-start" onClick={() => createClick()}>Create</button> :
                                null
                            }

                            {values.departmentId != 0 ?
                                <button type="button" className="btn btn-primary float-start" onClick={() => updateClick()}>Edit</button> :
                                null
                            }

                        </div>

                    </div>
                </div>
            </div>

        </div>
    )
}

export default Department
naveed
  • 111
  • 8
  • It would help if you created a runnable code snippet that reproduces the issue you are seeing. – Serhii Holinei Dec 22 '21 at 14:18
  • @SerhiiHolinei i am sorry but i have dont know how to do that but here is the github link for code if that helps https://github.com/naveednaseer/delete_later/blob/master/frontend/src/components/Department.js thanks – naveed Dec 22 '21 at 14:27
  • 1
    @SerhiiHolinei i added another section with relevant code only – naveed Dec 22 '21 at 16:18

1 Answers1

1

I think the problem you are having is related to the fact that you invoke filterFn immediately after changing the state:

let changeDepartmentNameFilter = (e) => {
    console.log(e.target.value)
    setValues({...values, 'departmentNameFilter': e.target.value})
    filterFn()
}

departmentNameFilter will not be updated synchronously. It means that filterFn() will be called with the previous state.

There are different approaches to your problem. For instance, you can pass values you want to filter into filterFn(newState) and use it as an argument:



let filterFn = (newValues) =>{
    let departmentIdFilter = newValues.departmentIdFilter
    let departmentNameFilter = newValues.departmentNameFilter


    let filteredData = filteredDepartment.filter(
        function(el){
            return el.DepartmentId.toString().toLowerCase().includes(
                departmentIdFilter.toString().trim().toLowerCase()
            ) &&
            el.DepartmentName.toString().toLowerCase().includes(
                departmentNameFilter.toString().trim().toLowerCase()
            )

        }
    )
    setDepartment(filteredData)
}

let changeDepartmentNameFilter = (e) => {
    console.log(e.target.value)
    const newValues = {...values, 'departmentNameFilter': e.target.value};
    setValues(newValues)
    filterFn(newValues)
}


Or you can have a useMemo hook to filter the array each time the values change:

const filteredDepartment = useMemo(() =>{
    let departmentIdFilter = values.departmentIdFilter
    let departmentNameFilter = values.departmentNameFilter

    // Note, I renamed filteredDepartment to department
    return department.filter(
        function(el){
            return el.DepartmentId.toString().toLowerCase().includes(
                departmentIdFilter.toString().trim().toLowerCase()
            ) &&
            el.DepartmentName.toString().toLowerCase().includes(
                departmentNameFilter.toString().trim().toLowerCase()
            )

        }
    )

}, [values, department]

Serhii Holinei
  • 5,758
  • 2
  • 32
  • 46