How to login validation using my api in React Js - json

React JS
I'm new to react js
In my api there is username and password. If the user login, have to validate from my json value
handleSubmit(e) {
fetch('https://randomuser.me/api?results=1')
.then((response) => {
return response.json()
.then((json) => {
if (response.ok) {
return Promise.resolve(json)
}
return Promise.reject(json)
})
})
alert(json) not working to check the result.
How can i fetch the username and password in the response?
And how to take this next page if the user was logged in successfully ?
My full Code
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
const ReactCSSTG = CSSTransitionGroup;
class App extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: true
}
// Bindings
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRemount = this.handleRemount.bind(this);
}
handleSubmit(e) {
alert("dsa");
fetch('https://randomuser.me/api?results=1')
.then((response) => {
return response.json()
.then((json) => {
if (response.ok) {
return Promise.resolve(json)
}
return Promise.reject(json)
})
})
}
handleRemount(e) {
this.setState({
isVisible: true
}, function () {
console.log(this.state.isVisible)
});
e.preventDefault();
}
render() {
// const for React CSS transition declaration
let component = this.state.isVisible ? <Modal onSubmit={this.handleSubmit} key='modal' /> : <ModalBack onClick={this.handleRemount} key='bringitback' />;
return <ReactCSSTG transitionName="animation" transitionAppear={true} transitionAppearTimeout={500} transitionEnterTimeout={500} transitionLeaveTimeout={300}>
{component}
</ReactCSSTG>
}
}
// Modal
class Modal extends React.Component {
render() {
return <div className='Modal'>
<Logo />
<form onSubmit={this.props.onSubmit}>
<Input type='text' name='username' placeholder='username' />
<Input type='password' name='password' placeholder='password' />
<button> Sign In</button>
</form>
<a href='#'>Lost your password ?</a>
</div>
}
}
// Generic input field
class Input extends React.Component {
render() {
return <div className='Input'>
<input type={this.props.type} name={this.props.name} placeholder={this.props.placeholder} required />
<label htmlFor={this.props.name}></label>
</div>
}
}
// Fake logo
class Logo extends React.Component {
render() {
return <div className="logo">
<i><img src={logo} className="App-logo" alt="logo" /></i>
<span> Test </span>
</div>
}
}
// Button to brind the modal back
class ModalBack extends React.Component {
render() {
return (
<button className="bringitback" onClick={this.props.onClick} key={this.props.className}>Back to login page!</button>
);
}
}
export default App;
Thanks in Advance!

If you just want to catch data for now this will do the trick
fetch('https://randomuser.me/api?results=1')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
});

fetch('https://randomuser.me/api?results=1')
.then((response) => {
// check for status code from service if success
// set response in state such as login success
this.route.navigate(['/']);
})
.catch(error =>{
console.log(error);
});
})
Taking user to next page. Use react router for achieving this.
Step 1: Wrap your <App /> inside <BrowserRouter />
Now validate response if username/password are correct using service call.
Then this.route.navigate(['/']);
This will navigate user to home page of app after successful login.

Heres What I did, keep in mind I set up my backend with express/node.
I used Axios to fetch from my api.
onSubmit = (e) => {
e.preventDefault();
axios.get('API_PATH')
.then(res => {
const user = res.data[0].username;
const password = res.data[0].password;
const username = this.state.username;
const passwordEntered = this.state.password;
if(username === '' && passwordEntered === ''){
document.getElementById('status').innerHTML = '<p>Please Enter A Valid Username and Password</p>';
}else if(user === username && passwordEntered === password){
document.getElementById('status').innerHTML = '';
console.log(user, password)
}else{
document.getElementById('status').innerHTML = '<p>Please Enter A Valid Username and Password</p>';
}
})
.catch(error => {
console.log(error);
});
}
Here is the form I used.
<Form
>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>Username</Form.Label>
<Form.Control
type="text"
name="username"
id="username"
value={this.state.value}
onChange={this.handleChange}
>
</Form.Control>
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Password</Form.Label>
<Form.Control
type="text"
id="password"
name="password"
value={this.state.value}
onChange={this.handleChange}
/>
</Form.Group>
</Form.Row>
<Button className="btn btn-sm btn-light" onClick={this.onSubmit}>
<i style={redColor} className="fas fa-sign-in-alt"></i> Login
</Button>
</Form>

Related

Failed to create check box preview using defaultChecked in reactjs

I'am new using reactjs and looks like I am following the tutorial with old version of react. So, I have some roles with their permissions, the problem is when I want to make changes of the role permissions I need to preview them with previous checked permission. As you can see the image below I have the permissions data, but when I try to put them into checkbox using default checked there is nothing happen.
here is my code
RoleEdit.tsx
import axios from "axios";
import { SyntheticEvent, useEffect, useState } from "react";
import { Navigate, useParams } from "react-router-dom";
import Wrapper from "../../components/Wrapper";
import { Permission } from "../../models/permissions";
const RoleEdit = (props:any) => {
const [permissions, setPermissions] = useState([]);
const [selected, setSelected] = useState([] as number[]);
const [name, setName] = useState('');
const [redirect, setRedirect] = useState(false);
const {id} = useParams();
useEffect( () => {
(
async () => {
const response = await axios.get('permissions');
setPermissions(response.data);
const {data} = await axios.get(`roles/${id}`);
setName(data.name);
setSelected(data.permissions.map((p : Permission) => p.id));
}
)();
}, [id]);
const check = (id: number) => {
if(selected.some(s => s === id)){
setSelected(selected.filter(s => s !== id));
return;
}
setSelected([...selected, id]);
}
const submit = async (e: SyntheticEvent) => {
e.preventDefault();
await axios.post('roles', {
name,
permissions: selected
});
setRedirect(true);
}
if(redirect){
return <Navigate to="/roles"/>
}
return(
<Wrapper>
<form onSubmit={submit}>
<div className="mb-3 mt-3 row">
<label className="col-sm-2 col-form-label">Role Name</label>
<div className="col-sm-10">
<input className="form-control" defaultValue={name} onChange={e => setName(e.target.value)}/>
</div>
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">Permissions</label>
<div className="col-sm-10">
{permissions.map((p: Permission) => {
return(
<div className="form-check form-check-inline col-3" key={p.id}>
<input className="form-check-input" type={"checkbox"}
value={p.id}
defaultChecked={selected.some( s => s === p.id)}
onChange={()=> check(p.id)}/>
<label className="form-check-label">{p.name}</label>
</div>
)
})}
</div>
</div>
<button className="w-100 btn btn-lg btn-primary" type="submit">Save</button>
</form>
</Wrapper>
);
};
export default RoleEdit;
please help me solve the problem so I can continue the tutorial. Thankyou

how to Dynamic add field post with reactjs and axios post

I am working on Dynamic add field data submit with reactjs and axios. Its working fine but only on one filed when i want to add more field then the field added but when i put my data and want to post data then only one field working. i am using react and axios post for submit my form.
My code
import React from 'react';
import axios from 'axios';
import { Grid, Button } from "#material-ui/core/";
import Alert from '#material-ui/lab/Alert';
import CloseIcon from "#material-ui/icons/Close";
import TextField from "#material-ui/core/TextField";
import AddIcon from '#material-ui/icons/Add';
class FaqPage extends React.Component<{},any>{
constructor(props) {
super(props)
this.state = {
faqList:[{index: Math.random(), question:'', answer: ''}],
// question: '',
// answer: '',
questions: ['hello']
}
this.state = { values: [{question: '',response: ''}] };
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidUpdate(){
setTimeout(() => this.setState({errorMessage:''}), 40000);
setTimeout(() => this.setState({sucessMessage:''}), 40000);
}
uploadDocument = (e) => {
console.log(e);
}
handlequestionChange = event => {this.setState({ question: event.target.value })}
handleanswerNameChange = event => {this.setState({ answer: event.target.value })}
handleSubmit = event => {
event.preventDefault();
event.target.reset()
// const openDate = {userid: this.state.openDate};
// const closeDate = {fullname: this.state.closeDate};
// const listingDate = {usergroup: this.state.listingDate};
axios.post('https://api.com/api/faqs',
{
ipoId: '328',
faqList:[
{ question: this.state.question,
answer: this.state.answer,
}
]
}
)
.then(res => {
console.log(res);
console.log(res.data);
console.log('thank you')
this.setState({sucessMessage: res.data});
})
.catch(err => {
this.setState({errorMessage: err.message});
})
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i} className="commonInput">
<div className="formW">
<TextField type="text" label="question" name="question" onChange={this.handlequestionChange}/>
</div>
<div className="formW">
<TextField type="text" label="answer" name="answer" onChange={this.handleanswerNameChange}/>
</div>
{
i ?
<button type="button" className="button remove" onClick={() => this.removeClick(i)}><CloseIcon /></button>
: null
}
</div>
)
}
handleChange (i,event) {
let values = [...this.state.values];
values[i][event.target.id] = event.target.value;
this.setState({ values });
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, {question: '',response: '',}]}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
componentDidMount() {
axios.get(`https://api.com/api/get/all`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<Grid className="CoomonT">
<div className="clapse ">
<form onSubmit={this.handleSubmit}>
<br/>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
{/* <div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
onClick={this.addClick.bind(this)}
>
<AddIcon/>
</Button>
</div> */}
{/* <div>file<TradeImportComponent/></div> */}
{/* <button type="submit" color="primary">Add</button> */}
<div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
type="submit"
disableElevation
>
Submit
</Button>
</div>
</form>
</div>
</Grid>
)
}
}
export default FaqPage;
Screenshot
Why are you using this.state two times? Each class component in React has only 1 state. So first of all, you should correct your state definition. Moreover, Your values state is an Array. So when you want to edit your question/answer or post data via axios, you should use the whole values array.
There are also some questions that you should answer to yourself to have a cleaner code. I implemented some general changes and commented those questions in the below code. Answer them and change code based on their answer, so that your code works.
import axios from 'axios';
import React from 'react';
import { Grid, Button } from "#material-ui/core/";
import Alert from '#material-ui/lab/Alert';
import CloseIcon from "#material-ui/icons/Close";
import TextField from "#material-ui/core/TextField";
import AddIcon from '#material-ui/icons/Add';
class FaqPage extends React.Component<{},any>{
constructor(props) {
super(props)
// What is defference between faqList and values? Could'nt you use just one of them? and build the other one from another one (whenever needed)?
this.state = {
faqList:[{index: Math.random(), question:'', answer: ''}],
values: [{question: '',response: ''}]
}
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidUpdate(){
setTimeout(() => this.setState({errorMessage:''}), 40000);
setTimeout(() => this.setState({sucessMessage:''}), 40000);
}
uploadDocument = (e) => {
console.log(e);
}
handleQuestionChange = (event, index) => {
const faq = this.state.values
faq[index].question = event.target.value
this.setState(faq)
}
handleAnswerNameChange = (event, index) => {
const faq = this.state.values
faq[index].answer = event.target.value
this.setState(faq)
}
handleSubmit = event => {
event.preventDefault();
event.target.reset()
// What is ipoId? Is it different from the `index` field in `this.state.faqList`?
axios.post('https://api.com/api/faqs',
{
ipoId: '328',
faqList:this.state.value
}
)
.then(res => {
console.log(res);
console.log(res.data);
console.log('thank you')
this.setState({sucessMessage: res.data});
})
.catch(err => {
this.setState({errorMessage: err.message});
})
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i} className="commonInput">
<div className="formW">
<TextField type="text" label="question" name="question" onChange=(e, i) => {this.handleQuestionChange(i)}/>
</div>
<div className="formW">
<TextField type="text" label="answer" name="answer" onChange=(i) => {this.handleAnswerNameChange(e, i)}/>
</div>
{
i ?
<button type="button" className="button remove" onClick={() => this.removeClick(i)}><CloseIcon /></button>
: null
}
</div>
)
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, {question: '',response: '',}]}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
componentDidMount() {
axios.get(`https://api.com/api/get/all`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<Grid className="CoomonT">
<div className="clapse ">
<form onSubmit={this.handleSubmit}>
<br/>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
{/* <div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
onClick={this.addClick.bind(this)}
>
<AddIcon/>
</Button>
</div> */}
{/* <div>file<TradeImportComponent/></div> */}
{/* <button type="submit" color="primary">Add</button> */}
<div className="form-btn formW">
<Button
size="small"
variant="contained"
className=""
color="primary"
type="submit"
disableElevation
>
Submit
</Button>
</div>
</form>
</div>
</Grid>
)
}
}
export default FaqPage;

Integrate Ant Design Form with Modal

I am pretty new to React and JS, and I am currently trying to create a component to integrate the antd form with modal so that I could utilize the form functionalities such as "validation".
Here is my code:
The function to post the request:
import baseUrl from "./baseUrl";
export async function _postSchoolRollOutRequest(schoolRollOutRequestForm) {
try {
const response = await fetch(
`${baseUrl}/feedbacks/request/schoolRollOutRequest`,
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(schoolRollOutRequestForm),
}
);
const data = await response.json();
console.log("Post school roll out form success!");
return data;
} catch (e) {
console.log("Post school roll out form failed!", e);
}
}
The component of integrating the form with modal:
import React, { useState } from "react";
import { Modal, Button, Form, Input, Radio } from "antd";
import { _postSchoolRollOutRequest } from "../../api/feedbacksApi";
import "./PopUp.scss";
export default (props) => {
const FormItem = Form.Item;
const [visible, setVisible] = useState(false);
const showModal = () => {
setVisible(true);
};
const handleOk = (schoolRollOutRequestForm) => {
_postSchoolRollOutRequest(schoolRollOutRequestForm);
setVisible(false);
};
const handleCancel = () => {
setVisible(false);
};
return (
<>
<Button type="primary" onClick={showModal}>
Roll-out My School!
</Button>
<Modal
destroyOnClose={true}
visible={visible}
title="Roll-out Request"
onCancel={handleCancel}
footer={[
<Button
block
key="submit"
type="primary"
onClick={(feedbackSubmission) =>
handleOk({
shoolName: feedbackSubmission.shoolName,
otherFeedback: feedbackSubmission.otherFeedback,
contact: feedbackSubmission.contact,
})
}
>
Roll-out My School!
</Button>,
]}
width={400}
>
<div className={"modal-body center"}>
<Form layout="vertical">
<Form.Item
label="Schools Name"
name="schoolName"
rules={[{ required: true }]}
>
{<Input type="text" label="schoolName" placeholder="UT Austin" />}
</Form.Item>
<FormItem
label="Any other requirements/feedback (optional)"
name="otherFeedback"
>
{<Input type="textarea" placeholder="abcd..." />}
</FormItem>
<FormItem label="How do we contact you? (optional)" name="contact">
{<Input type="text" placeholder="abcd#email.com" />}
</FormItem>
</Form>
</div>
</Modal>
</>
);
};
However, I encountered two problems that really confused me:
I think the button at the footer does not trigger the form's onFinish so that the form's validation does not work, I am wondering could I get any clue about the best practice for my situation?
I tried to fake a json for "handleOk" then later "_postSchoolRollOutRequest", but it seems like my backend get a request with an empty payload, could I get any insights about this problem as well?
Code Sandbox:
https://codesandbox.io/s/antdesignmodalform-stackoverflow-3yv4h?file=/index.js:920-3529
Firstly submit button should be inside form tag. If it is outside form tag then you need to make use of form attribute to trigger it.
In your case modal is always outside the form, so you have to link submit button with the form.
Here is how you can achieve it using ANT design.
Action Handler Code (if you are using redux then modify callback part as per your requirement)
export async function _postSchoolRollOutRequest(
schoolRollOutRequestForm,
callback
) {
const baseUrl = "http://testing.com";
console.log("form values", schoolRollOutRequestForm);
try {
const response = await fetch(
`${baseUrl}/feedbacks/request/schoolRollOutRequest`,
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(schoolRollOutRequestForm)
}
);
const data = await response.json();
console.log("Post school roll out form success!");
callback(response.status, data);
} catch (e) {
callback(e.status);
console.log("Post school roll out form failed!", e);
}
}
Form component
const FormModal = () => {
const [form] = Form.useForm();
const [visible, setVisible] = useState(false);
const [postData, setPostData] = useState({
loading: false,
error: false,
data: []
});
const onSubmit = (values) => {
setPostData({ ...postData, loading: true, error: false });
_postSchoolRollOutRequest(values, (status, data) => {
if (status === 200) {
form.resetFields();
setPostData({ ...postData, loading: false, data: data });
} else {
setPostData({
...postData,
loading: false,
error: true,
data: "Post school roll out form failed!"
});
}
});
};
return (
<>
<Button
type="primary"
onClick={() => {
setVisible(true);
}}
>
click to open form
</Button>
<Modal
visible={visible}
title="Post data"
okText="Submit"
cancelText="Cancel"
onCancel={() => {
setVisible(false);
}}
footer={[
<Button key="cancel" onClick={() => setVisible(false)}>
Cancel
</Button>,
<Button
key="submit"
type="primary"
loading={postData.loading}
onClick={() => {
form
.validateFields()
.then((values) => {
onSubmit(values);
})
.catch((info) => {
console.log("Validate Failed:", info);
});
}}
>
Submit
</Button>
]}
>
<Form
form={form}
layout="vertical"
name="form_in_modal"
initialValues={{
modifier: "public"
}}
>
<Form.Item
label="Schools Name"
name="schoolName"
rules={[
{
required: true,
message: ""
}
]}
>
<Input />
</Form.Item>
<Form.Item
label="Any other requirements/feedback (optional)"
name="otherFeedback"
>
<Input type="textarea" />
</Form.Item>
<Form.Item label="How do we contact you? (optional)" name="contact">
<Input />
</Form.Item>
{postData.error && (
<>
<br />
<span style={{ color: "red" }}>{postData.data}</span>
</>
)}
</Form>
</Modal>
</>
);
};

TypeError: links.map is not a function React

I'm working with reactjs typescript and cannot seem to prevent this error when trying to display JSON data from the server:
import React, { useRef, useState } from "react";
import useHttp from "../hooks/usehttp";
const HomePage: React.FC = () => {
const [links, setLinks] = useState([]);
const ref = useRef<HTMLInputElement>(null);
const { request } = useHttp();
const pressHandler = async (event: React.KeyboardEvent) => {
if (event.key === "Enter") {
try {
const data = await request(
"http://localhost:5000/api/link/generate-guest",
"POST",
{ from: ref.current!.value },
{}
);
alert(data.message);
console.log(data.link.to); // the link => localhost:5000/jshdadsa
setLinks(data.link.to);
console.log(links); // shows undefined ?????
} catch (error) {
alert(error);
}
}
};
return (
<>
<div className="row">
<div className="col s8 offset-s2" style={{ paddingTop: "2rem" }}>
<div className="input-field">
<input
placeholder="Enter link"
id="link"
type="text"
ref={ref}
onKeyPress={pressHandler}
/>
<label htmlFor="link">Enter link</label>
</div>
<div>
{ {links.map((link: any) => {
return (
<ul className="collection with-header">
<li className="collection-item">{link}</li>
</ul>
);
})} }
</div>
</div>
</div>
</>
);
};
export default HomePage;
Not sure what i am missing.
Use this code in order to update the array of link in your example:
setLinks([...links, data.link.to])

Open and close expandable button in list view

I have a list of Messages that you should be able to click and expand more for info. At the moment, my implementation expands/collapses all messages by clicking on any message.
I tried using the code below:
this.state = {
activeIndex:0,
isExpandable:false
}
And applying the condition as:
{!this.state.isExpandable && this.state.activeItem === i} to the map() where i was retrieving properties of each object.
image of buttons in collapsable state
image of buttons in expanded state
import React, { Component } from 'react'
import { Card, Feed } from 'semantic-ui-react'
import { Input } from 'react-input-component';
import { Collapse, Button} from 'reactstrap';
import styled from 'styled-components';
function searchingForName(search){
return function(x){
return x.firstName.toLowerCase().includes(search.toLowerCase()) || x.lastName.toLowerCase().includes(search.toLowerCase()) || !search ;
}
}
class Home extends Component {
constructor(props){
super(props);
this.state = {
results:[],
search:'',
collapse:false,
newSearch:'',
tags:[],
isExpandable:false,
activeIndex:0
}
this.onchange = this.onchange.bind(this);
this.toggle = this.toggle.bind(this);
this.inputKeyDown = this.inputKeyDown.bind(this);
// this.handleKeyPress = this.handleKeyPress.bind(this);
}
onchange = e => {
console.log(this.state.search)
this.setState({search:e.target.value});
}
// handleKeyPress = e => {
// if(e.key === 'Enter'){
// this.setState({newSearch: e.target.value});
// }
// }
inputKeyDown = (e) => {
const val = e.target.value;
if(e.key === 'Enter' && val){
if (this.state.tags.find(tag => tag.toLowerCase() === val.toLowerCase())) {
return;
}
this.setState({tags: [...this.state.tags,val]});
this.tagInput.value=null;
}
}
toggle(){
this.setState({collapse: !this.state.collapse});
}
componentDidMount(){
fetch('https://www.hatchways.io/api/assessment/students')
.then(res => res.json())
.then(data => {
console.log(data.students);
this.setState({results:data.students})
}).catch(err => {
console.log(err);
});
}
render() {
return (
<div>
<Card style={{'marginTop':'40px','width':'520px','marginRight':'auto','marginLeft':'auto'}}>
<Card.Content>
<Input
style={{'width':'519px'}}
placeholder="Search by name..."
onChange={this.onchange}
/>
<Input
style={{'width':'519px'}}
placeholder="Search by tags..."
onChange={this.onchange}
/>
{this.state.results.length ?
this.state.results.filter(searchingForName(this.state.search)).map((value,i) => (
<Feed>
<Feed.Event style={{'margin':'10px'}}>
<Image>
<Feed.Label image={value.pic} />
</Image>
<div style={{'float':'right'}}>
{!this.state.collapse ?
<Button onClick={this.toggle}>+</Button>
: <Button onClick={this.toggle}>-</Button>}
</div>
<Feed.Content style={{'textAlign':'center','marginBottom':'10px'}}>
<Feed.Summary><strong>{value.firstName.toUpperCase()} {value.lastName.toUpperCase()}</strong></Feed.Summary>
<Feed.Summary>Email: {value.email}</Feed.Summary>
<Feed.Summary>Company: {value.company}</Feed.Summary>
<Feed.Summary>Skill: {value.skill}</Feed.Summary>
<Feed.Summary>Average : {value.grades.map((x,i,arr)=> {
return x/arr.length;})
.reduce((a,b) => {
return a + b;
}) + "%"}
</Feed.Summary><br />
<Collapse isOpen={this.state.collapse}>
<Feed.Summary>
{Array.isArray(value.grades) && value.grades.map(val => {
return <div>Test {value.grades.indexOf(val)} : {parseFloat(val) + "%"}</div>
})}
</Feed.Summary><br />
{this.state.tags.map((tag,index) => (
<div>
<span className="addTag"key={index}>{tag}</span>
</div>
))}<br />
<input
type="text"
onKeyDown={this.inputKeyDown}
ref={c => { this.tagInput = c; }}
placeholder="add a tag..."
/>
{/* <div>{this.state.newSearch}</div><br />
<Input
style={{'width':'200px'}}
placeholder="add a tag..."
value={this.state.newSearch}
onKeyPress={this.handleKeyPress}
/> */}
</Collapse>
<hr/>
</Feed.Content>
</Feed.Event>
</Feed>
)) : ''}
</Card.Content>
</Card>
</div>
)
}
}
const Image = styled.div`
border: 1px solid #001;
border-radius: 60px;
overflow:hidden;
padding:18px;
height:90px;
width: 90px;
margin-top:30px;
margin-right:auto;
margin-left:auto;
margin-bottom:20px;
`
export default Home;
What is causing them all to expand/collapse at once and how can i change that to only expand/collapse the button is clicked?
Your main problem is that you don't have isOpened card for every student. You can only open all or none with one single collapse state. I have updated your code with solution here:
https://codesandbox.io/s/peaceful-kapitsa-tr9yn
I have changes toggle function, which takes index as parameter and updates single students card status - isOpened true or false.
toggle(index) {
const results = this.state.results.map((item, idx) => {
if (index === idx) {
return {
...item,
isOpened: !item.isOpened
};
}
return item;
});
this.setState({ results });
}
When you load all students data from API endpoint, you have to map through all items and add default isOpened state (by default I've added false - closed).
componentDidMount() {
fetch("https://www.hatchways.io/api/assessment/students")
.then(res => res.json())
.then(data => {
console.log(data.students);
const results = data.students.map(student => {
return {
...student,
isOpened: false
};
});
this.setState({ results });
})
.catch(err => {
console.log(err);
});
}
In render() method I have updated every item to check not this.state.collapse, but student.isOpened on Collapse component and toggle button.
Toggle button
<div style={{ float: "right" }}>
{!value.isOpened ? (
<Button onClick={() => this.toggle(i)}>+</Button>
) : (
<Button onClick={() => this.toggle(i)}>-</Button>
)}
</div>
Collapse component
<Collapse isOpen={value.isOpened}>
...
</Collapse>