Can't remove the value and uncheck the item of checkbox? - javascript

Maybe the question is a little bit confusing because I'm confused. The problem I have listed categories in the database I fetched it and create a post. Now I'm trying to edit the post. The categories are in checkbox format if check it adds the setCategories state if uncheck it will remove from the state. I have fetched the post and saved categories for that particular post. I've shown them checked. Now I'm trying to change the categories I've added. I'm successful to add more but cannot remove it as well am unable to uncheck the checkbox. Please check this code...
I'm highlighted the onChange part with dashes
here is code
import React, { useEffect, useState } from 'react';
import { Alert, Button, Card, Container, Form } from 'react-bootstrap';
import ReactMarkdown from 'react-markdown';
import { useDispatch, useSelector } from 'react-redux';
import { toast, ToastContainer } from 'react-toastify';
import { listCategory } from '../actions/categoryActions';
import { listPostDetails, updatePost } from '../actions/postActions';
const EditPost = ({ history, match }) => {
const postId = match.params.id;
const [categories, setCategories] = useState([]);
const dispatch = useDispatch();
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
const categoryList = useSelector((state) => state.categoryList);
const { categories: cateList } = categoryList;
useEffect(() => {
if (!userInfo) {
history.push('/login');
}
if (!post || post._id !== postId) {
dispatch(listPostDetails(postId));
} else {
setCategories(post.categories);
console.log(categories);
}
dispatch(listCategory());
}, [dispatch, history, userInfo, post, postId, categories]);
const resetHandler = () => {
setTitle('');
setImg('');
setCategories('');
setDesc('');
};
const submitHandler = (e) => {
e.preventDefault();
dispatch(updatePost(postId, title, desc, img, categories));
resetHandler();
history.push('/my_posts');
};
return (
<div className=" createPost mt-4 py-4">
<ToastContainer />
<Container>
<h2>EDIT POST</h2>
<Form onSubmit={submitHandler}>
<Form.Group controlId="category" className="mb-2">
<Form.Label>Select Categories</Form.Label>
<br />
{cateList?.map((cate) => (
<Form.Check
inline
key={cate._id}
type="checkbox"
label={cate.name}
checked={categories.includes(cate.name)}
------------------------------------------------------------------------------------------
onChange={(e) => {
if (e.target.checked) {
setCategories([categories.push(cate.name)]);
} else {
setCategories(
categories?.filter((cat) => cat !== cate.name)
);
}
}}
-------------------------------------------------------------------------------------------
/>
))}
</Form.Group>
<Button
type="submit"
variant="success"
style={{ letterSpacing: '2px', fontWeight: 'bold' }}>
UPDATE
</Button>
</Form>
</Container>
</div>
);
};
export default EditPost;

I think the problem is on useEffect method you are console.log(categories) it keeps on refreshing the state and not allowing you to add or remove items. first remove the console.log(categories) and also categories dependencies from useEffect and use this setCategories([...categories, cate.name]); instead of this setCategories([categories.push(cate.name)]);. You shouldn't change categories directly

You shouldn't change categories directly. So, instead of
setCategories([categories.push(cate.name)]);
try
setCategories([...categories, cate.name]);

Related

how to fetch data from API in react and search from the api?

I am trying to fetch this API dataset https://kimiquotes.herokuapp.com/quotes in react. I want to allow the user to search from the API using the id. whenever the user clicks on the search button I want to change the color of the search button. after the user enters the id and clicks the search button I want to fetch the dataset and display it in a li list I want to display the id, quotes, and year. Here is the code that I have right now but it's not working.
import "mvp.css";
import React, { useState, useEffect } from "react";
import axios from "axios";
import { Input } from "semantic-ui-react";
function City() {
const [APIData, setAPIData] = useState([]);
const [filteredResults, setFilteredResults] = useState([]);
const [searchInput, setSearchInput] = useState("");
useEffect(() => {
axios.get(`https://kimiquotes.herokuapp.com/quotes`).then((response) => {
setAPIData(response.data);
});
}, []);
const searchItems = (searchValue) => {
setSearchInput(searchValue);
if (searchInput !== "") {
const filteredData = APIData.filter((item) => {
return Object.values(item).join("").toLowerCase().includes(searchInput);
});
setFilteredResults(filteredData);
} else {
setFilteredResults(APIData);
}
};
return (
<div style={{ padding: 20 }}>
<Input
style={{ backgroundColor: "DodgerBlue" }}
icon="search"
placeholder="Search for 2008, 2012 or 2013 "
onChange={(e) => searchItems(e.target.value)}
/>
<div itemsPerRow={3} style={{ marginTop: 10 }}>
{searchInput.length > 1
? filteredResults.map((item) => {
const { id, quote, year } = item;
return (
<div>
<div>
<h1>ID: {id}</h1>
<li>QUOTE: {quote}</li>
<li>YEAR: {year}</li>
</div>
</div>
);
})
: APIData.map(() => {
return <h1></h1>;
})}
</div>
</div>
);
}
export default function App() {
return <City />;
}
```
`
The api is not responding for single values
const URL = https://kimiquotes.herokuapp.com/quotes?s=${searchValue};
instead of supplying the value dynamically try once with manually providing the value
const URL = https://kimiquotes.herokuapp.com/quotes?s=1;
and see in the console are you getting the value for the requested id.
function handleInput(){
console.log("From onclick -" +search);
fetch(`https://kimiquotes.herokuapp.com/quotes?id=1`)
.then((res)=>res.json())
.then((data)=>console.log(data));
}
I tried to get a single record, but failed.

Trying to display one element from an Array -ReactJs

I am trying to make a flashcard web app for language learning and/or rote learning. I have managed to show the first element of the array which contains the data that I'm fetching from the backend but I can't switch from the first element to the subsequent elements.
Here is my code in React:
// Decklist component that displays the flashcard
import { React, useEffect, useState, useContext } from "react";
import Card from "./Card";
import cardContext from "../store/cardContext";
const axios = require("axios");
export default function Decklist() {
//State for data fetched from db
const [data, setData] = useState([]);
//State for array element to be displayed from the "data" state
const [position, setPosition] = useState(0);
//function to change the array element to be displayed after user reads card
const setVisibility = () => {
setPosition(position++);
};
//function to change the difficulty of a card
const difficultyHandler = (difficulty, id) => {
console.log(difficulty);
setData(
data.map((ele) => {
if (ele.ID === id) {
return { ...ele, type: difficulty };
}
return ele;
})
);
};
//useEffect for fetching data from db
useEffect(() => {
axios
.get("/api/cards")
.then((res) => {
if (res.data) {
console.log(res.data);
setData(res.data.sort(() => (Math.random() > 0.5 ? 1 : -1)));
}
})
.catch((err) => {
console.log(err);
});
}, []);
return (
<cardContext.Provider
value={{ cardData: data, setDifficulty: difficultyHandler }}
>
{data.length && (
<Card
position={position}
// dataIndex={index}
visible={setVisibility}
id={data[position].ID}
front={data[position].Front}
back={data[position].Back}
/>
)}
</cardContext.Provider>
);
}
//Card component
import { React, useState, useEffect } from "react";
import Options from "./Options";
export default function Card(props) {
//State for showing or hiding the answer
const [reverse, setReverse] = useState(false);
const [display, setDisplay] = useState(true);
//function for showing the answer
const reversalHandler = () => {
setReverse(true);
};
return (
<div>
{reverse ? (
<div className="card">
{props.front} {props.back}
<button
onClick={() => {
props.visible();
}}
>
Next Card
</button>
</div>
) : (
<div className="card">{props.front}</div>
)}
<Options
visible={props.visible}
reverse={reversalHandler}
id={props.id}
/>
</div>
);
}
//Options Component
import { React, useContext, useState } from "react";
import cardContext from "../store/cardContext";
export default function Options(props) {
const ctx = useContext(cardContext);
const [display, setDisplay] = useState(true);
return (
<>
<div className={display ? "" : "inactive"}>
<button
onClick={() => {
setDisplay(false);
props.reverse();
ctx.setDifficulty("easy", props.id);
}}
>
Easy
</button>
<button
onClick={() => {
setDisplay(false);
props.reverse();
ctx.setDifficulty("medium", props.id);
}}
>
Medium
</button>
<button
onClick={() => {
setDisplay(false);
props.reverse();
ctx.setDifficulty("hard", props.id);
}}
>
Hard
</button>
</div>
</>
);
}
The setVisibility function in the Decklist component is working fine and setting the position state properly. However, I don't know how to re-render the Card component so that it acts on the position state that has changed.
One way to force a re-render of a component is to set its state to itself
onClick={() => {
props.visible();
setReverse(reverse);
}}
However this probably isn't your issue as components will automatically re-render when their state changes or a parent re-renders. This means that for some reason the Card component isn't actually changing the parent component.

How to set retrived checkbox value checked and others unchecked?

I have some posts in my database I'm trying to retrieve and edit posts. The posts had some categories which I set as a checkbox. Well, I've retrieved a single post by id successfully but the problem is I also retrieved the categories and I want to show them as checked not all of them only those ones which are set for that particular post. I have another problem I cannot check the box anymore and am not able to add another category to the category list. Help me!
Here is the Edit Post page
import React, { useEffect, useState } from 'react';
import { Alert, Button, Card, Container, Form } from 'react-bootstrap';
import ReactMarkdown from 'react-markdown';
import { useDispatch, useSelector } from 'react-redux';
import { toast, ToastContainer } from 'react-toastify';
import { listCategory } from '../actions/categoryActions';
import { listPostDetails, updatePost } from '../actions/postActions';
const EditPost = ({ history, match }) => {
const postId = match.params.id;
const [categories, setCategories] = useState([]);
const dispatch = useDispatch();
const categoryList = useSelector((state) => state.categoryList);
const { categories: cateList } = categoryList;
const postDetails = useSelector((state) => state.postDetails);
const { post } = postDetails;
useEffect(() => {
if (!userInfo) {
history.push('/login');
}
dispatch(listCategory());
if (!post || post._id !== postId) {
dispatch(listPostDetails(postId));
} else {
setCategories(post.categories);
}
}, [dispatch, history, userInfo, post, postId, categories]);
const submitHandler = (e) => {
e.preventDefault();
dispatch(updatePost(title, desc, img, categories));
history.push('/my_posts');
};
return (
<div className=" createPost mt-4 py-4">
<ToastContainer />
<Container>
<h2>EDIT POST</h2>
<Form onSubmit={submitHandler}>
<Form.Group controlId="category" className="mb-2">
<Form.Label>Select Categories</Form.Label>
<br />
{cateList?.map((cate) => (
<Form.Check
inline
key={cate._id}
type="checkbox"
label={cate.name}
onChange={(e) => {
if (e.target.checked) {
setCategories([...categories, cate.name]);
} else {
setCategories(
categories?.filter((cat) => cat !== cate.name)
);
}
}}
/>
))}
</Form.Group>
<Button
type="submit"
variant="success"
style={{ letterSpacing: '2px', fontWeight: 'bold' }}>
CREATE
</Button>
</Form>
</Container>
</div>
);
};
export default EditPost;

Can I fix the issue when I call an api, it called two times with reactjs?

I used redux-saga and I want when I click on my button, the api will be fetching,
My code is:
// #flow
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import { Row, Col, Card, CardBody, Button, ButtonDropdown, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { Translate } from 'src/components';
import { VCS } from 'src/common';
import { ACCESS_LEVELS, USER_RIGHTS, userAccess } from 'src/constants/user-rights';
import * as Actions from './actions';
import ClientUsersRSuiteTable from './components/client-users-rsuite-table';
import './users.scss';
function Users({ clientId, clientUsers, requestClientUsersData, getUserTemplate, pageParameters, ...props }) {
const [searchValue, setSearchValue] = useState('');
useEffect(() => {
requestClientUsersData({ id: clientId, pageParams: null });
}, []);
const handleChangeSearchValue = (input) => {
const search = input != '' ? input : null;
setSearchValue(search);
};
const [dropdownOpen, setDropdownOpen] = useState(false);
const toggle = () => setDropdownOpen(prevState => !prevState);
return (
<>
<VCS hasRights={[userAccess(ACCESS_LEVELS.EDIT, USER_RIGHTS.API_CLIENTS)]}>
<div className="row">
<div className="col">
<Button
style={{ backgroundColor: '#ffffff !important', color: '#fa5c7c !important' }}
outline
color="danger"
className="mb-2 mr-1 btn-user-template"
onClick={() => getUserTemplate(clientId)}
>
<i className="mdi mdi-file-outline mr-1" size="large" />
<Translate id="pages.client.users.get.user.template" />
</Button>
</div>
</div>
</div>
</VCS>
</>
);
}
Users.defaultProps = {
};
const mapStateToProps = (state) => ({
clientUsers: state.Administration.users.clientUsers ? state.Administration.users.clientUsers :
state.Administration.clients.clientUsers,
pageParameters: state.Administration.users.clientUsersPageParameters ? state.Administration.users.clientUsersPageParameters :
state.Administration.clients.clientUsersPageParameters
});
export default connect(mapStateToProps, Actions)(Users);
My api is:
export const getUserTemplate = async (clientId) => request(`api/clients/${clientId}/users/import/template`, 'GET');
When I click on the button, my api is called two times with same response !
The Api is to export excel data, when I run it, I get :
I want when I run it on clicking the button, I get just one file not two(because it runs two time)
How can I fix it ?

How to pass id into navlink in react JavaScript

I am fetching details from database and displaying on page and I want to create an edit button which after click can open that details in editable form. In my case that editable form is (EMPLOYEEFORM).
Can you please suggest how to pass id into edit button so the button can take data to edit area.
I am having problem. Right not I have pass id to navlink but its gives me error like employee not found with this id. I am new to reactjs. I tried passing id value but its not acting properly and I am not so aware of passing id into navlink or button. Can you please suggest some direct code or and valuable link where can I update my knowledge.
import React, { useEffect, useState } from 'react';
import './employees.css';
import routePaths from '../../shared/routePaths';
import { getEmployeeDetails } from '../../shared/services/apiService';
import { useParams, NavLink, Redirect } from 'react-router-dom';
import { Descriptions , Card , Divider, Row , Col , Button} from 'antd';
import { isSuccess } from '../../shared/utils/jsHelper';
import { EditTwoTone } from '#ant-design/icons';
const { Meta } = Card;
const employeeDescription = () => {
const {id} = useParams();
const [loading, setLoading] = useState(false);
const [empName, setEmpName] = useState([]);
const [empEmail, setEmpEmail] = useState([]);
const [empPhone, setEmpPhone] = useState([]);
useEffect(() => {
if (id) {
getEmployee();
}
}, [id]);
const getEmployee = () => {
setLoading(true);
getEmployeeDetails(id).then((resp) => {
if (isSuccess(resp)) {
const employee = resp.data.data;
setEmployeeValues(employee);
}
}).finally(() => setLoading(false));
};
const setEmployeeValues = (employee) => {
setEmpName(employee.empName);
setEmpEmail(employee.empEmail);
setEmpPhone(employee.empPhone);
};
return(
<div>
<Card
title="Employee Info"
extra={[
<NavLink to={'${routePaths.EMPLOYEEFORM}/${employee.id}'} className="lin">
<Button key="1">
<EditTwoTone twoToneColor="#000" /> Edit Employee Details
</Button>
</NavLink>,
<NavLink to={routePaths.EMPLOYEES} className="lin">
<Button key="2">
{'<<'} Back to Employee List
</Button>
</NavLink>,
]}
>
<h6>
<strong>Pesonal Details :</strong>
</h6>
<Divider />
<Descriptions className="card-tis">
<Descriptions.Item label="Name ">{empName}</Descriptions.Item>
<Descriptions.Item label="Email ">{empEmail}</Descriptions.Item>
<Descriptions.Item label="Phone ">{empPhone}</Descriptions.Item>
</Descriptions>
</Card>
</div>
);
};
export default employeeDescription;
You can merge all of the states in one state of employee instead of maintaining state for each employee property.
In the provided code you are using signle (') quotes in the navlink instead of backticks. Which will not resolve the variable and you will get a plain string like ${routePaths.EMPLOYEEFORM}/${employee.id}.
I have made few changes please try.
import React, { useEffect, useState } from 'react';
import './employees.css';
import routePaths from '../../shared/routePaths';
import { getEmployeeDetails } from '../../shared/services/apiService';
import { useParams, NavLink, Redirect } from 'react-router-dom';
import { Descriptions, Card, Divider, Row, Col, Button } from 'antd';
import { isSuccess } from '../../shared/utils/jsHelper';
import { EditTwoTone } from '#ant-design/icons';
const { Meta } = Card;
const employeeDescription = () => {
const { id } = useParams();
const [loading, setLoading] = useState(false);
const [employee, setEmployee] = useState({});
useEffect(() => {
if (id) {
getEmployee();
}
}, [id]);
const getEmployee = () => {
setLoading(true);
getEmployeeDetails(id)
.then((resp) => {
if (isSuccess(resp)) {
const employee = resp.data.data;
setEmployee(employee);
}
})
.finally(() => setLoading(false));
};
return (
<div>
<Card
title="Employee Info"
extra={[
<NavLink to={`${routePaths.EMPLOYEEFORM}/${employee.id}`} className="lin">
<Button key="1">
<EditTwoTone twoToneColor="#000" /> Edit Employee Details
</Button>
</NavLink>,
<NavLink to={routePaths.EMPLOYEES} className="lin">
<Button key="2">
{'<<'} Back to Employee List
</Button>
</NavLink>,
]}
>
<h6>
<strong>Pesonal Details :</strong>
</h6>
<Divider />
<Descriptions className="card-tis">
<Descriptions.Item label="Name ">{employee.empName}</Descriptions.Item>
<Descriptions.Item label="Email ">{empEmail.empEmail}</Descriptions.Item>
<Descriptions.Item label="Phone ">{empPhone.empPhone}</Descriptions.Item>
</Descriptions>
</Card>
</div>
);
};
export default employeeDescription;

Categories