Search bar does not retrieve data from mongodb collection - reactjs

I am trying to use the data store in mongodb collection and render it in the front end. It renders the text box, labels and search button, even though it does not load any of the data. My collection name is users and my database CRDU works perfectly fine.
Please help me with this, below is my front end search.js
function Search(){
const [resultUsers, setResultUsers] = useState([]);
const [usersTable, setUsersTable] = useState([]);
const [searchP, setSearchP] = useState("");
const requestGet=async()=>{
await axios.get("mongodb://localhost:27017/projectDB/users/")
.then(response=>{
setResultUsers(response.data);
setUsersTable(response.data);
}).catch(error=>{
console.log(error);
})
}
const handleChange=e=>{
setSearchP(e.target.value);
filter(e.target.value);
}
const filter=(searchTerm)=>{
var searchResults=usersTable.filter((element)=>{
if(element.username.toString().toLowerCase().includes(searchTerm.toLowerCase())
|| element.firstName.toString().toLowerCase().includes(searchTerm.toLowerCase())
|| element.lastName.toString().toLowerCase().includes(searchTerm.toLowerCase())
){
return element;
}
});
setResultUsers(searchResults);
}
useEffect(()=>{
requestGet();
},[])
return (
<div className="Search">
{/* <Container> */}
<div className="containerInput">
<input
className="form-control search-input"
value={searchP}
placeholder="Enter username, first name or last name of the user to begin search"
onChange={handleChange} />
<button className="btn btn-success">Search for users
</button>
<br/>
</div>
{/* </Container> */}
<div className='tabled'>
<div className="table-responsive">
{/* <Container> */}
<table className="table table-sm table-bordered;">
<thead>
<tr>
<th>Username</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
{resultUsers &&
resultUsers.map((resultUsers)=>(
<tr key={resultUsers.id}>
<td>{resultUsers.username}</td>
<td>{resultUsers.firstName}</td>
<td>{resultUsers.lastName}</td>
</tr>
))}
</tbody>
</table>
{/* </Container> */}
</div>
</div>
</div>
)
}
export default Search
Thanks in advance!!

Related

ReactJS search with api params

I want to ask for your help.
Earlier I got a Reactjs search filter tutorial on a web which I forgot where the source came from.
the code is like this =>
import React, { useEffect, useState } from "react";
import axios from "axios";
const Users = () => {
const [users, setUsers] = useState([]);
const [mainUsers, setMainUsers] = useState([]);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((res) => {
setUsers(res.data);
setMainUsers(res.data);
})
.catch((err) => {
console.log(err);
});
}, []);
const handleSearch = (e) => {
setUsers(
mainUsers.filter((u) =>
u.name.toLowerCase().includes(e.target.value.toLowerCase())
)
);
console.log(e.target.value);
};
return (
<div className={`mt-5 p-4 container-fluid`}>
<div className="row my-2 mb-4 justify-content-between w-100 mx-0">
<div className="form-group col-10 col-md-6 col-lg-4">
<input
type="text"
className="form-control shadow"
placeholder="Search"
onChange={handleSearch}
/>
</div>
</div>
{users.length ? (
<table className="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">User Name</th>
<th scope="col">Email</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{users.map((u) => (
<tr key={u.id}>
<th scope="row">{u.id}</th>
<td>{u.name}</td>
<td>{u.username}</td>
<td>{u.email}</td>
<td>
<i className="fa fa-edit text-warning"></i>
<i className="fa fa-edit text-warning pointer"></i>
</td>
</tr>
))}
</tbody>
</table>
) : (
<h6 className="text-center text-info">wating ...</h6>
)}
</div>
);
};
export default Users;
then I have an endpoint that has params, like this =>
xxxx.com/api/dashboard/v1/getCountPoiCategoryProvinsi?provinsi=jakarta
The question is,
how to change the initial url (https://jsonplaceholder.typicode.com/users") to this url (xxxx.com/api/dashboard/v1/getCountPoiCategoryProvinsi?provinsi=jakarta) ?
I don't know how to change it Thank you, I really appreciate your help.

How to check an item and disable another checkbox in react?

I have a list of items from API. I also have two checkboxes to approve or decline an item. I want to be able to check the approve box and disable the decline box for an item.
function AllReferral() {
const [buttonStatus1, setButtonStatus1] = useState(false)
const [buttonStatus2, setButtonStatus2] = useState(false)
//function
const deactivateButton2 = () => setButtonStatus1(!buttonStatus1)
const deactivateButton1 = () => setButtonStatus2(!buttonStatus2)
return (
<section>
<div>
{user?.services?.length > 0 && (
<div>
<table>
<thead>
<tr>
<th >Approve</th>
<th >Decline</th>
<th >Service Name</th>
</tr>
</thead>
{user?.services?.map((item, index) => (
<tbody key={index}>
<tr>
<td>
<input
name={item?.name}
onClick={deactivateButton2}
type="checkbox"
value={checked}
onChange={(e) => setChecked(e.target.value)}
/>
</td>
<td>
<input
name={item?.name}
onClick={deactivateButton1}
type="checkbox"
value={checked2}
onChange={(e) => setChecked2(e.target.value)}
/>
</td>
<td>{item?.label}</td>
</tr>
</tbody>
))}
</table>
</div>
)}
</div>
</section>
);
}
Above is one of many trials I've done but I still don't get the desired action I need. I would appreciate some help
The easiest way to do this is to use a radio button. The default behavior of radio buttons is that if you select one radio button the others are automatically deselected.
If you want to have it as a checkbox, you can use a controlled input. Below is an example implementation that uses a shared state for the inputs.
function App () {
const [status, setStatus] = React.useState(false)
const handleChange = e => setStatus(prevState => !prevState)
return (
<div>
<label>
<input
type="checkbox"
checked={status}
onChange={handleChange}
/>
Accept
</label>
<label>
<input
type="checkbox"
checked={!status}
onChange={handleChange}
/>
Decline
</label>
</div>
)
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<div id="root"></div>

Message prints in every Dynamic Accordion in ReactJs

I have a dynamic Accordion in ReactJs. I am getting the message from my backend. but it's printing in every Accordion. I'm sharing the code
import React, { useState, useEffect } from "react";
import ApplicantDash from "./ApplicantDash";
import {
Accordion,
AccordionSummary,
AccordionDetails,
Typography,
} from "#material-ui/core";
import * as FcIcons from "react-icons/fc";
import ApplicantService from "../services/ApplicantService";
export default function AvailJobs() {
const [aplcntEmail, setAplcntEmail] = useState("aman#gmail.com"); //change to aplcntemail
const [isShow, setIsShow] = useState(false);
const [msg, setMsg] = useState([""]);
const [job, setJob] = useState([
{
jobTitle: "",
dateOfPosting: Date,
lastDateToApply: new Date().toLocaleDateString([], {
year: "numeric",
month: "long",
day: "numeric",
}),
preferableSkills: [],
requiredExp: 0,
recruiterEmail: "",
companyName: "",
companyAddress: "",
},
]);
useEffect(() => {
const data = ApplicantService.getAllJobs()
.then((response) => {
console.log(response.data);
setJob(response.data);
})
.catch((error) => {
alert(error.response.data);
});
}, []);
const onApplyButton = (item,key) => {
const data2 = ApplicantService.applyForJob(aplcntEmail, item)
.then((response) => {
console.log(response.data);
setIsShow(true);
setMsg(response.data)
})
.catch((error) => {
setIsShow(true);
setMsg(error.response.data);
});
};
return (
<div>
<ApplicantDash />
<div className="container bg-light">
<div className="card-bodies">
<section className="mb-4">
<h2 className="h1-responsive font-weight-bold text-center my-4">
All Available jobs
</h2>
</section>
{job.map((item, key) => (
<>
<Accordion key={key}>
<AccordionSummary
expandIcon={<FcIcons.FcExpand />}
aria-controls="panel1a-content"
id="panel1a-header"
className="Accordian"
>
<Typography>
<div className="d-flex p-1 justify-content-evenly">
<div className="p-1">
<b> Job: </b> {item.jobTitle}
</div>
<div className="p-2"></div>
<div className="p-1">
<b> Company: </b> {item.companyName}
</div>
<div className="p-2"></div>
<div className="p-1">
<b> Last Date: </b> {item.lastDateToApply}
</div>
</div>
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
<div className="container">
<table class="table table-borderless">
<tbody>
<tr>
<td>JOB TITLE</td>
<td>:</td>
<td>
<b>{item.jobTitle}</b>
</td>
</tr>
<tr>
<td>Company</td>
<td>:</td>
<td>
<b>{item.companyName}</b>
</td>
</tr>
<tr>
<td>Address</td>
<td>:</td>
<td>
<b>{item.companyAddress}</b>
</td>
</tr>
<tr>
<td>Last Date to Apply</td>
<td>:</td>
<td>
<b>{item.lastDateToApply}</b>
</td>
</tr>
<tr>
<td>Experience</td>
<td>:</td>
<td>
<b>{item.requiredExp}</b>
</td>
</tr>
<tr>
<td> Skills </td>
<td>:</td>
<td>
<table className="table table-condensed w-auto table-borderless table-hover">
{item.preferableSkills.map((S, index1) => {
return (
<tbody key={index1}>
<td scope="col">
{index1 + 1}.<b>{S}</b>
</td>
</tbody>
);
})}
</table>
</td>
</tr>
<tr>
<td></td>
<td></td>
<td>
<button
type="button"
class="btn btn-primary"
onClick={() => onApplyButton(item,key)}
>
Apply for the job{" "}
</button>
</td>
</tr>
</tbody>
{isShow && <>
{msg}
</>}
</table>
</div>
</Typography>
</AccordionDetails>
</Accordion>
</>
))}
</div>
</div>
</div>
);
}
Now when I click on Apply for this job button. The message I get from backend prints only to Active accordion
Here some pictures which might help.
enter image description here
As you can see the response from backend is prints in the both of the accordion
Issue
The issue here is that you've a single boolean isShow state and a single msg state, and all the accordion detail sections use the same single isShow state to conditionally render the msg state.
Solution
A simple solution would be to store the id, or title, or index, of the accordion to show the message of.
Example:
export default function AvailJobs() {
...
const [isShow, setIsShow] = useState({}); // <-- initially empty object
...
const onApplyButton = (item, key) => {
ApplicantService.applyForJob(aplcntEmail, item)
.then((response) => {
console.log(response.data);
setMsg(response.data);
})
.catch((error) => {
setMsg(error.response.data);
})
.finally(() => {
setIsShow(show => ({
...show,
[key]: true // <-- set true the specific key
}));
});
};
return (
<div>
...
{job.map((item, key) => (
<Accordion key={key}>
...
<AccordionDetails>
<Typography>
<div className="container">
<table class="table table-borderless">
<tbody>
...
<tr>
...
<td>
<button
type="button"
class="btn btn-primary"
onClick={() => onApplyButton(item, key)}
>
Apply for the job
</button>
</td>
</tr>
</tbody>
{isShow[key] && <>{msg}</>} // <-- check if isShow[key] is truthy
</table>
</div>
</Typography>
</AccordionDetails>
</Accordion>
))}
...
</div>
);
}

Rendering table's data header in reactjs

I could render the herader's table users through for exemple: {user[name]}. But I couldn't render the header itself who is the [name] for example rendering: name of Leanne Graham. Can anyone help me with this?
import React from 'react'
const Users= ({ users}) => {
return (
<div>
{users.map((user,index) => (
<div key={index}>
<div className="container smcontainer d-flex justify-content-start">
<div className="row">
<div className="col-md-12">
<table className="table table-striped">
<thead>
</thead>
<tbody>
<tr>
<td className=""> {user['id']} </td>
<td className=""> {user['name']} </td>
<td className=""> {user['username']} </td>
<td className=""> {user['email']} </td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
))}
</div>
)}
export default Products
This is the App component
class App extends Component {
constructor(props){
super(props)
this.state= {
users: [],
}
}
async componentDidMount() {
const url = ('https://jsonplaceholder.typicode.com/users')
const response = await fetch (url)
const data = await response.json()
this.setState({users: data.itemsList})
console.log({users: data.itemsList})
}
render() {
return (
<Users users = {this.state.users} />
)
}
}
export default App;
When you map over an array, whatever you return is returned each time for every element in the array. This code will create a whole new table for each user.
I think what you want to do is define your column headers separately from your map call and then map over the array to generate the rows:
const columns = ["ID", "Name", "Username", "Email"];
...
<div>
<div className="container smcontainer d-flex justify-content-start">
<div className="row">
<div className="col-md-12">
<table className="table table-striped">
<thead>
{columns.map(c => <th>{c}</th>)}
</thead>
<tbody>
{users.map((user, index) => (
<tr>
<td className=""> {user['id']} </td>
<td className=""> {user['name']} </td>
<td className=""> {user['username']} </td>
<td className=""> {user['email']} </td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
I made a Codepen demonstrating both ways, but to me the first one makes much more sense.
That should give you what you want.
<thead>
{user['name']}
<thead/>
If you want to take the first name of Leanne Graham, you can do:
<thead>
{user['name'].split(" ")[0]}
<thead/>

Display search results on keypress

I am tryng to display search results for each key press on my input:
getMovies(e){
axios.get(`http://www.omdbapi.com/?t=${e.target.value}`)
.then((response) => {
this.setState({ movies: response.data });
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<div className="container">
<SearchForm onkeydown={this.getMovies} />
<MovieList movies={this.state.movies}/>
</div>
);
}
}
In my search form I bind my function to the FormControl onChange:
export default class SearchForm extends React.Component{
render(){
return(
<Row>
<Col md={6} >
<h2>Custom search field</h2>
<div className="custom-search-input">
<Col md={12} className="input-group" >
<FormControl
type="text"
bsSize="lg"
value={this.props.val}
placeholder="Enter text"
onChange={this.props.onkeydown.bind(this)}
/>
<span className="input-group-btn">
<button className="btn btn-lg" type="button">
<i className="glyphicon glyphicon-search"></i>
</button>
</span>
</Col>
</div>
</Col>
</Row>)
}
}
My movielist component:
export default class MovieList extends React.Component{
render(){
var userNodes = this.props.movies.map(function(movie){
return (
<tr key={movie.id}>
<td>{movie.Year}</td>
<td >{movie.Title}</td>
<td >{movie.Released}</td>
</tr>
)
});
return (
<div>
<Table responsive>
<thead>
<tr>
<th>id</th>
<th>Year</th>
<th>Title</th>
<th>Released</th>
</tr>
</thead>
<tbody>
{userNodes}
</tbody>
</Table>
</div>
);
}
}
I can get the response on the network panel, but the state is not updating to display the MovieList component.
How can I update the state and display it in my MovieList ?
I've checked that API and seems it returns an object, not an array.
Update 1
You can convert your component in something like:
export default class MovieList extends React.Component{
render(){
const { movie } = this.props;
return (
<div>
<Table responsive>
<thead>
<tr>
<th>Id</th>
<th>Year</th>
<th>Title</th>
<th>Released</th>
</tr>
</thead>
<tbody>
<tr>
<td>{movie.imdbID}</td>
<td>{movie.Year}</td>
<td>{movie.Title}</td>
<td>{movie.Released}</td>
</tr>
</tbody>
</Table>
</div>
);
}
}
and use it like:
<MovieList movie={this.state.movies} />
Please notice I'm using movie instead of movies.
Update 2:
You can also (and I would suggest doing this) convert your MovieList into a dumb functional component:
const MovieList = ({ movie }) => (
<div>
<Table responsive>
<thead>
<tr>
<th>Id</th>
<th>Year</th>
<th>Title</th>
<th>Released</th>
</tr>
</thead>
<tbody>
<tr>
<td>{movie.imdbID}</td>
<td>{movie.Year}</td>
<td>{movie.Title}</td>
<td>{movie.Released}</td>
</tr>
</tbody>
</Table>
</div>
)
export default MovieList;

Resources