how to Dynamic add field post with reactjs and axios post - html

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;

Related

How i can do my component in React.js have a individual behavior?

I'm implementing a Like and Dislike Button, and I wanna that when I click them will be with other colors, but just the clicked component, when I click all buttons change the state, can anybody help me?
`
const indexPost = async () => {
const data = await api.get('/api/posts')
if(data.data.length !=0){
const dataArray = data.data
if(dataArray.length === 0) {
return
}else{
return(
setPost(dataArray.map( data => (
<Post key={data._id} id={data._id} title={data.title} text={data.text}>
<Like id={data._id}></Like>
</Post>
)))
)
}
}
}
export default function Like({itemId}) {
const context = useContext(notificationContext)
const {isLoved, Like, Loved, Unlike, isLike, isUnlike, setIsLike, setIsUnlike, setIsLoved } = context
return(
<div className={styles.likeContainer} key={itemId}>
{isLike ? (
<button className={styles.likeContent} onClick={() => setIsLike(false)}><Icon.ThumbsUp className={styles.Icon} fill="#5CB0BB" ></Icon.ThumbsUp></button>) :
(<button className={styles.likeContent} onClick={() => Like() }><Icon.ThumbsUp className={styles.Icon} ></Icon.ThumbsUp></button>)}
{isLoved ?
(<button className={styles.likeContent} onClick={() => setIsLoved(false)}><Icon.Heart className={styles.Icon} fill="red" ></Icon.Heart> </button>) :
(<button className={styles.likeContent} onClick={() => Loved() }><Icon.Heart className={styles.Icon} ></Icon.Heart></button>)}
{isUnlike ? (
<button className={styles.likeContent} onClick={() => setIsUnlike(false)}><Icon.ThumbsDown className={styles.Icon} fill="#702BA6" ></Icon.ThumbsDown> </button>) :
(<button className={styles.likeContent} onClick={() => Unlike()}><Icon.ThumbsDown className={styles.Icon} ></Icon.ThumbsDown></button>
)}
</div>
)
};
I have implemented the similar one in my project, it is very basic , it shows how to update the likes , you need to handle the cases of user authentication and stuff
App.js
import { useState, useEffect, createContext, useReducer } from "react";
import { updateArrayOfObj } from "./utils";
import AllPosts from "./AllPosts";
export const PostsContext = createContext();
const initialState = {
posts: [
{
_id: "1",
name: "Browny",
image: "http://placekitten.com/200/310",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "2",
name: "Blacky",
image: "http://placekitten.com/200/320",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "3",
name: "SnowWhite",
image: "http://placekitten.com/200/300",
likes: 0,
love: 0,
dislikes: 0
}
]
};
const reducer = (state, action) => {
switch (action.type) {
case "UPDATE_POST":
return {
...state,
posts: updateArrayOfObj(
state.posts,
action.payload.obj,
"_id",
action.payload._id
)
};
case "CREATE_POST":
return {
...state,
posts: [...state.posts, ...action.payload.data]
};
case "DELETE_POST":
return {
...state,
posts: state.posts.filter((ele) => ele._id !== action.payload._id)
};
default:
return state;
}
};
export default function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<PostsContext.Provider
value={{
state,
dispatch
}}
>
<div className="App">
<AllPosts />
</div>
</PostsContext.Provider>
);
}
PostsAll.js
import Post from "./Post";
import { PostsContext } from "./App";
import { useContext } from "react";
export default function AllPosts() {
const { state } = useContext(PostsContext);
return (
<div className="allPosts">
{state.posts.map((item) => {
return (
<Post
name={item.name}
image={item.image}
likes={item.likes}
love={item.love}
dislikes={item.dislikes}
id={item._id}
key={item._id}
/>
);
})}
</div>
);
}
Post.js
import { PostsContext } from "./App";
import { useContext } from "react";
export default function Post(props) {
const { state, dispatch } = useContext(PostsContext);
const handleUserInteraction = (type, id) => {
dispatch({
type: "UPDATE_POST",
payload: {
obj: { [type]: props[type] + 1 },
_id: id
}
});
};
return (
<div className="post">
<h3>{props.name}</h3>
<img src={props.image} alt="cat" />
<br />
<button onClick={() => handleUserInteraction("likes", props.id)}>
{props.likes} Like
</button>{" "}
<button onClick={() => handleUserInteraction("love", props.id)}>
{props.love} Love
</button>{" "}
<button onClick={() => handleUserInteraction("dislikes", props.id)}>
{props.dislikes} Dislike
</button>
</div>
);
}
You can refer to this codesandbox to implement the same
You can use onClick() on each like button and attach it with a function, then you can get the value of that particular like with e.currentTarget.id and change its css/style the way you want.
const handleClick=(e)=>
{
console.log(e.currentTarget.id);
}

HTML JavaScript React: Front-End React Component Throwing react-dom.development.js:506 Warning

I have rendered a front-end react / redux component using JSX syntax. It executes but throws the following warning in my console:
Below is my code:
import React from 'react'
import {connect} from 'react-redux'
import {getUsers, deleteUserThunk} from '../store/allUsers'
import {updateUserThunk, fetchSingleUser} from '../store/singleUser'
// Status Filter import BeerFilter from './BeerFilter'
import Card from 'react-bootstrap/Card'
import Button from 'react-bootstrap/Button'
import {UncontrolledCollapse} from 'reactstrap'
export class AllUsers extends React.Component {
constructor(props) {
super(props)
this.state = {
showForm: false,
stat: ''
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
componentDidMount() {
try {
this.props.fetchInitialUsers()
this.props.deleteUserThunk()
} catch (error) {
console.error(error)
}
}
clickHandlerOne() {
let hidden = this.state.showForm
this.setState({
showForm: !hidden
})
}
handleChange(event) {
//console.log('event.target', event.target)
this.setState({
[event.target.name]: event.target.value
})
}
async handleSubmit(userId) {
event.preventDefault()
const updatedUser = {
id: userId,
isAdmin: this.state.stat
}
// console.log('UPDATE USER', updatedUser)
await this.props.updateUserThunk(updatedUser)
this.props.fetchInitialUsers()
}
render() {
const users = this.props.users
// console.log('PROPS', this.props)
console.log('USERS', this.props.users)
return (
<div>
{/* <div className="options">
<select onChange={this.handleChange}>
<option value="">Sort By...</option>
<option value="priceHighToLow">Price (high to low)</option>
<option value="priceLowToHigh">Price (low to high)</option>
<option value="name">Name</option>
</select>
<BeerFilter />
</div> */}
<div className="flex-cards">
{users.map(user => (
<Card style={{width: '18rem'}} key={user.id}>
{/* delete thunk */}
<span>
<p>
<Button
id={`delete${user.id}`}
variant="danger"
onClick={() => this.props.deleteUserThunk(user.id)}
>
X
</Button>
</p>
</span>
<Card.Body>
<Card.Title>User Id: {user.id}</Card.Title>
<Card.Text>
<div>
<ul>
<li>
<div className="highlight">
<img src={user.imageUrl} />
</div>
<div className="details">
<p>Username: {user.username}</p>
<p>User Email: {user.email}</p>
<p>Admin Status: {user.isAdmin ? 'true' : 'false'}</p>
<p>
Created Date:{' '}
{new Intl.DateTimeFormat('en-GB', {
month: 'short',
day: '2-digit',
year: 'numeric'
}).format(new Date(user.createdAt))}
</p>
<p />
<Button
id={`user${user.id}`}
onClick={() => {
this.clickHandlerOne()
}}
variant="outline-info"
>
Admin Status Toggle
</Button>
<UncontrolledCollapse toggler={`#user${user.id}`}>
{/* {this.state.showForm && (
<UpdateUserStatus userId={user.id} />
)} */}
<form onSubmit={() => this.handleSubmit(user.id)}>
<div>
<span>
<select
name="stat"
value={
typeof user.isAdmin === 'string'
? this.state.isAdmin
: user.isAdmin
}
onChange={this.handleChange}
>
<option value="true">true</option>
<option value="false">false</option>
</select>
</span>
<p />
<span>
<p>
{/* */}
<button type="submit">Submit</button>
</p>
</span>
</div>
</form>
</UncontrolledCollapse>
</div>
</li>
</ul>
</div>
</Card.Text>
</Card.Body>
</Card>
))}
</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
users: state.allUsers
}
}
const mapDispatchToProps = dispatch => {
return {
loadSingleUser: id => dispatch(fetchSingleUser(id)),
updateUserThunk: updatedUser => dispatch(updateUserThunk(updatedUser)),
//getSortedBeers: (sortBy, beers) => dispatch(sortBeers(sortBy, beers)),
fetchInitialUsers: () => dispatch(getUsers()),
deleteUserThunk: userId => dispatch(deleteUserThunk(userId))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AllUsers)
In my web page I (not always but usually) have to click the edit button twice for my order status to update and render on my page. I'm wondering if the warning has anything to do with this.
What am I doing wrong? I am very new to this type of coding so specificity in responses would be greatly appreciated.
There are a few changes that I would make in addition to addressing your console error.
Bind this to clickHandlerOne
Don't use <p> tags for the sake of adopting their styling. Example:
This makes sense to me. It's a paragraph of text.
<p>Username: {user.username}</p>
This doesn't make sense to me. I think you're wanting a <button> with certain spacing styles:
<span>
<p>
<Button
id={`delete${user.id}`}
variant="danger"
onClick={() => this.props.deleteUserThunk(user.id)}
>
X
</Button>
</p>
</span>
Try out this code and see how it works:
import React from "react";
import { connect } from "react-redux";
import { getUsers, deleteUserThunk } from "../store/allUsers";
import { updateUserThunk, fetchSingleUser } from "../store/singleUser";
// Status Filter import BeerFilter from './BeerFilter'
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
import { UncontrolledCollapse } from "reactstrap";
export class AllUsers extends React.Component {
constructor(props) {
super(props);
this.state = {
showForm: false,
stat: ""
};
this.clickHandlerOne = this.clickHandlerOne.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
try {
this.props.fetchInitialUsers();
this.props.deleteUserThunk();
} catch (error) {
console.error(error);
}
}
clickHandlerOne() {
const hidden = this.state.showForm;
this.setState({
showForm: !hidden
});
}
handleChange(event) {
//console.log('event.target', event.target)
this.setState({
[event.target.name]: event.target.value
});
}
async handleSubmit(userId) {
// event.preventDefault(); // I don't think you ave an `event` in scope here
const updatedUser = {
id: userId,
isAdmin: this.state.stat
};
// console.log('UPDATE USER', updatedUser)
await this.props.updateUserThunk(updatedUser);
this.props.fetchInitialUsers();
}
render() {
const users = this.props.users;
// console.log('PROPS', this.props)
console.log("USERS", this.props.users);
return (
<div>
{/* <div className="options">
<select onChange={this.handleChange}>
<option value="">Sort By...</option>
<option value="priceHighToLow">Price (high to low)</option>
<option value="priceLowToHigh">Price (low to high)</option>
<option value="name">Name</option>
</select>
<BeerFilter />
</div> */}
<div className="flex-cards">
{users.map(user => (
<Card style={{ width: "18rem" }} key={user.id}>
{/* delete thunk */}
<div>
<Button
id={`delete${user.id}`}
variant="danger"
onClick={() => this.props.deleteUserThunk(user.id)}
>
X
</Button>
</div>
<Card.Body>
<Card.Title>User Id: {user.id}</Card.Title>
<Card.Text>
<div>
<ul>
<li>
<div className="highlight">
<img src={user.imageUrl} />
</div>
<div className="details">
<p>Username: {user.username}</p>
<p>User Email: {user.email}</p>
<p>Admin Status: {user.isAdmin ? "true" : "false"}</p>
<p>
Created Date:{" "}
{new Intl.DateTimeFormat("en-GB", {
month: "short",
day: "2-digit",
year: "numeric"
}).format(new Date(user.createdAt))}
</p>
<Button
id={`user${user.id}`}
onClick={() => {
this.clickHandlerOne();
}}
variant="outline-info"
>
Admin Status Toggle
</Button>
<UncontrolledCollapse toggler={`#user${user.id}`}>
{/* {this.state.showForm && (
<UpdateUserStatus userId={user.id} />
)} */}
<form onSubmit={() => this.handleSubmit(user.id)}>
<div>
<select
name="stat"
value={
typeof user.isAdmin === "string"
? this.state.isAdmin
: user.isAdmin
}
onChange={this.handleChange}
>
<option value="true">true</option>
<option value="false">false</option>
</select>
<div>
{/* */}
<button type="submit">Submit</button>
</div>
</div>
</form>
</UncontrolledCollapse>
</div>
</li>
</ul>
</div>
</Card.Text>
</Card.Body>
</Card>
))}
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
users: state.allUsers
};
};
const mapDispatchToProps = dispatch => {
return {
loadSingleUser: id => dispatch(fetchSingleUser(id)),
updateUserThunk: updatedUser => dispatch(updateUserThunk(updatedUser)),
//getSortedBeers: (sortBy, beers) => dispatch(sortBeers(sortBy, beers)),
fetchInitialUsers: () => dispatch(getUsers()),
deleteUserThunk: userId => dispatch(deleteUserThunk(userId))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(AllUsers);
To get the styles that you were relying on from the <p>, you can inline styles, or use CSS via the className prop.
There's also a few CSS-in-JS libraries to be aware of, such as styled-components.
Let me know if this fixes your issue.
<Card.Text> renders a <p> and you have plenty of <div>'s nested there.
I also spotted an issue in handleSubmit function. You are calling event.preventDefault() but you are not passing the event is undefined.

Render input fields dynamically inside a list

I have set of components where it would consist of input fields along with text rows.
As given in the image the users should be able to add categories and description. After adding them they will be rendered as a list of components. like this
Inside a category there will be tags as given in the above image and to add them i have to add a input component. This input component should be available only when the user clicks on the Add tag button below each category row. When a user clicks on it,it should enable the input(should render a input component inside the selected category row) and should be able to type the tag name on it and save it. I need to make this input field enable only when i click on the add tag button. and it should enable only in the selected category row. This is the code that i have tried.
import React, { Component, Fragment } from "react";
import { Button, Header, Input } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import ReactDOM from "react-dom";
class App extends Component {
state = {
category: "",
description: "",
categories: []
};
onChange = (e, { name, value }) => {
this.setState({ [name]: value });
};
addCategory = () => {
let { category, description } = this.state;
this.setState(prevState => ({
categories: [
...prevState.categories,
{
id: Math.random(),
title: category,
description: description,
tags: []
}
]
}));
};
addTag = id => {
let { tag, categories } = this.state;
let category = categories.find(cat => cat.id === id);
let index = categories.findIndex(cat => cat.id === id);
category.tags = [...category.tags, { name: tag }];
this.setState({
categories: [
...categories.slice(0, index),
category,
...categories.slice(++index)
]
});
};
onKeyDown = e => {
if (e.key === "Enter" && !e.shiftKey) {
console.log(e.target.value);
}
};
tags = tags => {
if (tags && tags.length > 0) {
return tags.map((tag, i) => {
return <Header key={i}>{tag.name}</Header>;
});
}
};
enableTagIn = id => {};
categories = () => {
let { categories } = this.state;
return categories.map(cat => {
return (
<Fragment key={cat.id}>
<Header>
<p>
{cat.title}
<br />
{cat.description}
</p>
</Header>
<Input
name="tag"
onKeyDown={e => {
this.onKeyDown(e);
}}
onChange={this.onChange}
/>
<Button
onClick={e => {
this.addTag(cat.id);
}}
>
Add
</Button>
{this.tags(cat.tags)}
</Fragment>
);
});
};
render() {
return (
<Fragment>
{this.categories()}
<div>
<Input name="category" onChange={this.onChange} />
<Input name="description" onChange={this.onChange} />
<Button onClick={this.addCategory}>Save</Button>
</div>
</Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
This is the codesandbox url.
Any idea on how to achieve this?.
I changed your code by using function components and react hooks and i created category component which has it own state like this:
import React, { Fragment } from "react";
import { Button, Header, Input } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import ReactDOM from "react-dom";
const App = () => {
const [Category, setCategory] = React.useState({
title: "",
description: ""
});
const [Categories, setCategories] = React.useState([]);
return (
<div>
{console.log(Categories)}
<Input
value={Category.title}
onChange={e => setCategory({ ...Category, title: e.target.value })}
/>
<Input
value={Category.description}
onChange={e =>
setCategory({ ...Category, description: e.target.value })
}
/>
<Button onClick={() => setCategories([...Categories, Category])}>
Save
</Button>
<div>
{Categories.length > 0
? Categories.map(cat => <CategoryItem cat={cat} />)
: null}
</div>
</div>
);
};
const CategoryItem = ({ cat }) => {
const [value, setvalue] = React.useState("");
const [tag, addtag] = React.useState([]);
const [clicked, setclicked] = React.useState(false);
const add = () => {
setclicked(false);
addtag([...tag, value]);
};
return (
<Fragment>
<Header>
<p>
{cat.title}
<br />
{cat.description}
</p>
</Header>
<Input
name="tag"
value={value}
style={{ display: clicked ? "initial" : "none" }}
onChange={e => setvalue(e.target.value)}
/>
<Button onClick={() => (clicked ? add() : setclicked(true))}>Add</Button>
<div>{tag.length > 0 ? tag.map(tagname => <p>{tagname}</p>) : null}</div>
</Fragment>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
and here a sandbox

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>

How to login validation using my api in React Js

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>