I am building an simple todo app to practise reactjs I have 3 components which looks like this:
Here is the TodoAppComponent.js which is the wrapper of the other two components:
import AddTodoComponent from '../AddTodoComponent/AddTodoComponent';
class TodoAppComponent extends Component {
render() {
return (
<div id="page-content-wrapper">
<div className="container">
<div className="row">
<div className="col-lg-6 col-lg-offset-3">
<h1 className="m-b-md">What needs to be done?</h1>
<AddTodoComponent></AddTodoComponent>
</div>
</div>
</div>
</div>
);
}
}
export default TodoAppComponent;
An AddTodoComponent.jsx where I can add an todo:
import TodoItemComponent from '../TodoItemComponent/TodoItemComponent';
class AddTodoComponent extends Component {
constructor(props) {
super(props);
this.state = {
todo: '',
todoArray: []
};
}
addTodo(e){
this.setState({ todo: e.target.value });
this.state.todoArray.push(<TodoItemComponent todo={this.state.todo}></TodoItemComponent>);
}
handleChange(e) {
this.setState({ todo: e.target.value });
}
render() {
return (
<div>
<div className="input-group m-b-md">
<input type="text" className="form-control add-todo" placeholder="Todo..." value={this.state.todo} onChange={this.handleChange.bind(this)} />
<span className="input-group-btn">
<button className="btn btn-react" type="button" onClick={this.addTodo.bind(this)}>Add</button>
</span>
</div>
<ul className="list-group">
{this.state.todoArray}
</ul>
</div>
);
}
}
export default AddTodoComponent;
As you see I push the TodoItemComponent to an state array.
Here is the TodoItemComponent.jsx:
class TodoItemComponent extends Component {
deleteTodo(){
// this.setState({
// data: update(this.state.data, {$splice: [[index, 1]]})
// })
}
render() {
console.log(this.props.todo, this.props.title);
return (
<div>
<li className="list-group-item todo-item">
<button className="btn btn-xs btn-react btn-circle m-r-md">
<span className="fa fa-check"></span>
</button>
{this.props.todo}
<span className="pull-right">
<button className="btn btn-xs btn-react btn-circle m-r-xs">
<span className="fa fa-pencil-square-o"></span>
</button>
<button className="btn btn-xs btn-react btn-circle" onClick={this.deleteTodo()}>
<span className="fa fa-trash-o"></span>
</button>
</span>
</li>
</div>
);
}
}
export default TodoItemComponent;
As you see I have a button where I can delete the todo item. But how can I acces the state in this file to delete it from the state array?
you can try this
deleteTodo(){
this.props.onDelete(this.props.todo);
}
and in yourAdddTodoComponent
addTodo(e){
this.setState({ todo: e.target.value });
this.state.todoArray.push(<TodoItemComponent onDelete={this.delete} todo={this.state.todo}></TodoItemComponent>);
}
delete:function(index)
{
this.setState({
// data: update(this.state.data, {$splice: [[index, 1]]})
// })
}
Related
How can we list data from the array list on the same page in button click using react?
When user enter quantity setting value text box change event
class ProductList extends Component {
constructor(props) {
super(props);
this.state={
CartArray:[],
ProductList:[],
}
}
handleInputChange = event =>
{
const cart_values = event.target.name.split('-');
let newCart = {};
newCart["Key"]=cart_values[0]
newCart["ProductName"]=cart_values[1]
newCart["ProductBrand"]=cart_values[2]
this.setState(prevState => ({CartArray: [...prevState.CartArray, newCart]}))
}
viewCart = () => {
//What need to write here show data from CartArray:[] to my basket
}
}
Below is my render method. Numerical text box change i am setting in state value
render() {
return (
<div className="card" style={{ marginBottom: "10px"}}>
<div> <button className="btn btn-sm btn-warning float-right" onClick={this.viewCart}>View cart</button></div>
{this.state.ProductList.map((product, key) =>(
<div className="card-body">
<div className="card-title" key={key} value={key}>{product.ProductName}
<img src= {`data:image/jpeg;base64,${product.Image2}`} width="200" height="80" />{product.Brand}
<div>
<button className="btn btn-sm btn-warning float-right"
onClick={this.addToCart}>Add to cart</button>
<div>
<input type="number" min="0" pattern="[0-9]*" onInput={this.handleInputChange.bind(this)} name={`Name${key}-${product.ProductName}-${product.Brand}`} />
</div>
</div>
</div>
</div>
))}
</div>
)
}
If by show you mean to show on screen, not inside viewCart but in separate method render()
render(){
return(
<div>
{
this.state.CartArray.map((product) => {
<p>Key: {product.Key} </p>
<p>ProductName: {product.ProductName} </p>
<p>ProductBrand: {product.ProductBrand} </p>
})
}
</div>
);
}
I'm building a simple hotel reviews app in React. I had it set up to display the first 3 reviews with the button "See all" to expand the box to see the rest of the reviews. However, I noticed that every time I try to submit a review, the last review in the first 3 reviews didn't show up in the rest of the reviews shown upon expansion. I tried a variety of solutions but couldn't solve it.
Here's my working demo: http://immense-beach-76879.herokuapp.com/
Here's my github repo: https://github.com/kikidesignnet/hotelreviews
Here is my code.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// import '/css/style.css';
/* An example React component */
class App extends Component {
constructor(props) {
super(props);
//Initialize the state in the constructor
this.state = {
name: "",
reviews: [],
otherReviews: [],
open: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.renderReviews = this.renderReviews.bind(this);
this.toggleReviews = this.toggleReviews.bind(this);
// this.addReviews = this.addReviews.bind(this);
}
// handle change
handleChange(e) {
this.setState({
name: e.target.value
});
console.log('onChange', this.state.name);
}
handleSubmit(e) {
// stop browser's default behaviour of reloading on form submit
e.preventDefault();
axios
.post('/reviews', {
name: this.state.name
})
.then(response => {
console.log('from handle submit', response);
// set state
this.setState({
reviews: [response.data, ...this.state.reviews].slice(0,3),
name: "",
otherReviews: [response.data, ...this.state.reviews].slice(3).concat([...this.state.otherReviews])
});
});
}
renderReviews() {
return this.state.reviews.map(review => (
<div key={review.id} className="media innercard">
<div className="media-body">
<div className="profile_box">
<div className="profile_img">
<img src="/images/profilepic.png" alt="" />
</div>
<div className="profile_data">
<h3>{review.user.name}</h3>
<span className="text-muted">
{this.convertTime(review.updated_at)}
</span>
</div>
</div>
<p>{review.name}</p>
</div>
</div>
));
}
//get all the reviews from backend
getReviews(){
axios.get('/reviews').then(response => this.setState({
reviews: [...response.data.reviews].slice(0,3),
otherReviews: [...response.data.reviews].slice(3)
}));
}
toggleReviews() {
this.setState({open: !this.state.open});
}
//lifecycle method
componentDidMount(){
this.getReviews();
}
render() {
return (
<div className="container">
<div className="row justify-content-center">
<div className="col-md-8">
<div className="review_card">
<div className="card-body">
<form onSubmit={this.handleSubmit} className="comment_form">
<div className="form-group">
<i className="fas fa-comment-dots"></i>
<input
onChange={this.handleChange}
value = {this.state.name}
className="form-control"
placeholder="Comment"
required
/>
</div>
<div className="btn_align">
<button type="submit" className="btn red_btn">
Submit
</button>
</div>
</form>
<div className="reviews_list">
<div className="review_header">
<h1>Reviews</h1>
<button className="toggle_btn" onClick={this.toggleReviews}>{this.state.open ? 'Hide reviews' : 'See all'}</button>
</div>
{this.renderReviews()}
{this.state.open && this.state.otherReviews.map(review =>(
<div key={review.id} className="media innercard">
<div className="media-body">
<div className="profile_box">
<div className="profile_img">
<img src="/images/profilepic.png" alt="" />
</div>
<div className="profile_data">
<h3>{review.user.name}</h3>
<span className="text-muted">
{this.convertTime(review.updated_at)}
</span>
</div>
</div>
<p>{review.name}</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default App;
This is the code that I'm trying to edit to show the submitted review in the box.
handleSubmit(e) {
// stop browser's default behaviour of reloading on form submit
e.preventDefault();
axios
.post('/reviews', {
name: this.state.name
})
.then(response => {
console.log('from handle submit', response);
// set state
this.setState({
reviews: [response.data, ...this.state.reviews].slice(0,3),
name: "",
otherReviews: [response.data, ...this.state.reviews].slice(3).concat([...this.state.otherReviews])
});
});
}
How do I solve this and what am I doing it wrong?
I am trying to get a modal to function the modal I am trying to mirror is available here.
https://codesandbox.io/s/n9zn3n43o0
The button for the modal is displaying however the modal itself is not.
Here is my exact code for this function.
class App extends React.Component {
constructor(props) {
console.log("Props - ", props);
super(props);
this.state = {
modalVisible: false
};
this.openModal = this.openModal.bind(this);
}
openModal() {
console.log("Open modal called ", this.state.modalVisible);
const modalVisible = !this.state.modalVisible;
this.setState({
modalVisible
});
}
render() {
let styles = this.state.modalVisible
? { display: "block" }
: { display: "none" };
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button
type="button"
onClick={this.openModal}
className="btn btn-info btn-lg"
>
Open Modal
</button>
<div
id="myModal"
className="modal fade in"
role="dialog"
style={styles}
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
onClick={this.openModal}
className="close"
>
×
</button>
<h4 className="modal-title">Modal Header</h4>
</div>
<div className="modal-body">
<p>Some text in the modal.</p>
</div>
<div className="modal-footer">
<button
onClick={this.openModal}
type="button"
className="btn btn-default"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
And here is the code of the whole page
import React from "react";
import { Link } from "react-router-dom";
import Popup from "reactjs-popup";
import { Button, ButtonToolbar, Modal } from "react-bootstrap";
import ReactDOM from "react-dom";
import AddWorkstation from "./UpdateUserWorkStationDetailsForm";
class DisplayUserAcountDetails extends React.Component {
constructor() {
super();
this.state = { AccountDetails: [] };
}
// sets the questions form sql into state for questions
getItems() {
var user = window.localStorage.getItem("User");
if (user) {
fetch(`/profile-work-station-detailss/${user}`)
.then(recordset => recordset.json())
.then(results => {
this.setState({ AccountDetails: results.recordset });
});
} else {
alert("user not set");
}
}
//when the component mounts make the sql questions the
componentDidMount() {
this.setState({
AccountDetails: this.getItems()
});
}
render() {
try {
return (
<>
<h3 style={{ textAlign: "center" }}> Workstations</h3>
<button></button>
{this.state.AccountDetails ? (
<ul>
<App /> // calling it here
<Popup
style={{ width: "300px" }}
trigger={<button> Help?</button>}
closeOnDocumentClick
className={"tooltipBoundary"}
>
<AddWorkstation />
</Popup>
<Link to="/update-work-station-details">
<button style={{ float: "right" }}>+</button>
</Link>
<br />
<br />
{this.state.AccountDetails &&
this.state.AccountDetails.map(function(AccountDetails, index) {
return (
<div className="jumbotron">
<h3>Work Station</h3>
<li> Location: {AccountDetails.DeskLocation}</li>
<li>
ExtraInformation: {AccountDetails.ExtraInformation}
</li>
<li>
Primary Work Station:
{AccountDetails.PrimaryWorkStation}
</li>
<li> Date Added: {AccountDetails.PrimaryWorkStation}</li>
<li>
<Link to="/update-work-station-details">
<button>Update Account Details</button>
</Link>
</li>
</div>
);
})}
</ul>
) : (
<ul>
<div className="jumbotron">
<h3>Work Station</h3>
<li> Email: Null </li>
<li> Name: Null </li>
<li> Contact Number: Null </li>
<li>
<Link to="/update-work-station-details">
<button>Update Accoudnt Details</button>
</Link>
</li>
</div>
</ul>
)}
</>
);
} catch (e) {
console.log(e);
}
}
}
export default DisplayUserAcountDetails;
class App extends React.Component {
constructor(props) {
console.log("Props - ", props);
super(props);
this.state = {
modalVisible: false
};
this.openModal = this.openModal.bind(this);
}
openModal() {
console.log("Open modal called ", this.state.modalVisible);
const modalVisible = !this.state.modalVisible;
this.setState({
modalVisible
});
}
render() {
let styles = this.state.modalVisible
? { display: "block" }
: { display: "none" };
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button
type="button"
onClick={this.openModal}
className="btn btn-info btn-lg"
>
Open Modal
</button>
<div
id="myModal"
className="modal fade in"
role="dialog"
style={styles}
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
onClick={this.openModal}
className="close"
>
×
</button>
<h4 className="modal-title">Modal Header</h4>
</div>
<div className="modal-body">
<p>Some text in the modal.</p>
</div>
<div className="modal-footer">
<button
onClick={this.openModal}
type="button"
className="btn btn-default"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
I have tried multiple examples but this issue still persists.
Is there something I am missing ?
Any help greatly appreciated.
Hope this helps someone this is the code I have used instead and it worked fine.
class Header extends React.Component {
constructor(props) {
super(props);
this.handleClose = this.handleClose.bind(this);
this.handleShow = this.handleShow.bind(this);
this.state = {
show: false
};
}
handleClose() {
this.setState({
show: false
});
}
handleShow() {
this.setState({
show: true
});
}
render() {
// console.log(this.state);
return (
<div className="header-container">
<Button onClick={this.handleShow}>LOGIN</Button>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal Header</Modal.Title>
</Modal.Header>
<Modal.Body>Modal Body</Modal.Body>
</Modal>
</div>
);
}
}
I'm making a page where I need to make multiple selections of buttons (like a filter, which I'll use for the next page).
the information from these buttons is coming from an array and I'm using .map () to mount the button list.
My problem is how do I change the state of only the button that was clicked. The way it is now, when I click, all the buttons are active.
How can I solve this?
Thank you.
import React from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { getLevel, getDiscipline } from '../../functions';
import template from './index.pug';
export default class ConfigAssessment extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
constructor(props){
super(props);
this.state = {
level: getLevel(),
discipline: getDiscipline(),
active: '',
first_click: true,
}
}
changeActive = () => {
if (this.state.first_click === true) {
this.setState({
active: 'active',
first_click: false
});
} else {
this.setState({
active: '',
first_click: true,
});
}
}
render() {
return(
<div className="configuration">
<div className="config-title">
<i className="ti-settings" />
<h2>
<FormattedMessage {...messages.configAssessment} />
</h2>
</div>
<div className="config-items">
<div className="form-group">
<label>
<FormattedMessage {...messages.level} />
</label>
<div className="row">
{this.state.level.map((level, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={level.id}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
id={level.id}
onClick={this.changeActive}
>
{level.level}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.discipline} />
</label>
<div className="row">
{ this.state.discipline.map((discipline, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={i}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
{discipline.discipline}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.selectQuestion} />
</label>
<div className="row">
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeAutomatic} />
</button>
</div>
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeManual} />
</button>
</div>
</div>
</div>
<div className="form-group fg-right">
<Link className="btn btn-warning" to="#">
<FormattedMessage {...messages.createAssessment} />
</Link>
</div>
</div>
</div>
);
}
}
Create a separate component for button
class MyButton extends Component {
constructor(props){
super(props);
this.state = {
person: this.props.person
}
}
buttonActiveHandler = () => {
let oldStatus = this.props.person.status;
this.props.person.status = (!oldStatus ? 'active': '');
this.setState({
person:this.props.person
});
}
render() {
return (
<button className={this.state.person.status} onClick={this.buttonActiveHandler}>{this.state.person.name}</button>
);
}
}
export default MyButton;
Then import button component. use map function to for your code block
<div className={classes.Box}>
<h4>Lorem, ipsum.</h4>
{
this.props.survey.map((person, i) => {
return (
<MyButton key={i} person={person}/>
)
})
}
</div>
The easiest solution to this problem is making the component of the content inside the map and then handling the state of that component there. Hence it will maintain individual states.
It depends what you need.
You can create separate component for button with state.
You can also keep state of each button in react state as an array, and then you can get the state of each button by index.
I'd recommend the first solution, it'd easier to manage such state, but it will be harder to get the state of a specific button from the parent component.
I was using React and Typescript. I installed react-datepicker and imported into my code. This error occurred:
module can't find react-datepicker
But I have react-datepicker module in node_module. why does the error occure?
I'm using TSX file method.
todo.component.tsx
import * as React from 'react';
import * as classNames from 'classnames';
import TodoList from './todo.list';
import { Todo } from './../todo.interface';
import { Button } from 'react-bootstrap';
import DatePicker from 'react-datepicker';
import moment from 'moment';
import 'react-datepicker/dist/react-datepicker.css';
const KEYCODE_ENTER = 13;
export default class TodoComponent extends React.Component
<TodoComponentProps, TodoComponentState> {
constructor(props) {
super(props);
this.state = {
description: '',
valid: true,
items: [], text: '',
startDate: '',
};
this.removeTodos = this.removeTodos.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(date) {
this.setState({
startDate: date
});
}
addTodos(e) {
e.preventDefault();
this.setState({
items: [this.state.text, ...this.state.items],
text: ''
});
}
removeTodos(name, i) {
let items = this.state.items.slice();
items.splice(i, 1);
this.setState({
items
});
}
updateValue(e) {
this.setState({ text: e.target.value })
}
openNav() {
document.getElementById("mySidenav").style.width = "250px";
console.log(this)
}
closeNav() {
document.getElementById("mySidenav").style.width = "0";
}
setDescription(event) {
this.setState({ valid: true, description: event.target.value });
}
addTodo(event) {
if (event && event.keyCode !== KEYCODE_ENTER && event.type !== 'click') {
return;
}
if (!this.state.description.length || this.state.description.length > 50) {
this.setState({ valid: false });
} else {
this.props.addTodo(this.state.description);
this.setState({ description: '' });
}
}
render() {
let inputClass = classNames('form-group', {
'has-error': !this.state.valid
});
return (
<div>
<div className="container" onKeyDown={this.addTodo.bind(this)}>
<div className="row">
<div className="col-sm-12">
<h2 className="text-center">What do you need to do?</h2>
<br />
<br />
</div>
<div className="col-sm-6 col-sm-offset-3">
<div className={inputClass}>
<label className="control-label">Task description</label>
<input className="form-control input-lg" type="text" value={this.state.description} onChange={this.setDescription.bind(this)} />
</div>
</div>
<div className="col-sm-3 col-sm-offset-3">
<button className="btn btn-success btn-block" onClick={this.addTodo.bind(this)}>
<i className="fa fa-plus"></i> Add Todo
</button>
</div>
<div className="col-sm-3">
<button className="btn btn-danger btn-block" onClick={this.props.removeDoneTodos.bind(this)}>
<i className="fa fa-trash-o"></i> Remove done todos
</button>
</div>
</div>
<br />
<br />
<div className="row">
<div className="col-sm-6 col-sm-offset-3" onClick={this.openNav.bind(this)}>
<TodoList {...this.props} />
</div>
</div>
<div id="mySidenav" className="row offcanvas">
<div className="sideNav">
<span onClick={this.closeNav.bind(this)}><i className="fa fa-lg fa-close"></i></span>
<br /><br />
<div className="due">
<DatePicker
inline
selected={this.state.startDate}
onChange={this.handleChange}
/>
</div>
<hr />
<div className="remind">
</div>
<hr />
<div className="sublist" >
<TodosubList items={this.state.items} removeTodos={this.removeTodos} />
<form onSubmit={(e) => this.addTodos(e)}>
<input
placeholder="Add SubTask"
value={this.state.text}
onChange={(e) => { this.updateValue(e) }}
/>
<button type="submit">+</button>
</form>
</div>
<hr />
<div className="description">
</div>
<hr />
<div className="comment">
</div>
<hr />
<div className="commentIn">
</div>
</div>
</div>
</div>
</div>
);
}
}
class TodosubList extends React.Component<{ items?: any; removeTodos: any; }, {}> {
removeItem(item, i) {
this.props.removeTodos(item, i);
}
render() {
return (
<ul className="sub">
{this.props.items.map((todo, i) => {
return <li onClick={() => { this.removeItem(todo, i) }} key={i}>{todo}</li>
})}
</ul>
);
}
}
interface TodoComponentProps {
todos: Todo[];
addTodo(description: string): void;
addTodos?: any;
toggleTodo: React.MouseEventHandler;
editTodo: React.MouseEventHandler;
removeTodo: React.MouseEventHandler;
removeDoneTodos: React.MouseEventHandler;
}
interface TodoComponentState {
description?: string;
subdescription?: any;
valid?: boolean;
items?: any;
text?: any;
startDate?: any;
}
cmd error:
error:cant find module react-datepicker.
I think you need to npm install #types/react-datepicker.