Updating Table in React - reactjs

Seen a few questions but still not sure what to do. New to react as well. I want to update a table with the values of Title and Amount using input fields. I am pretty sure I have to set the state to a blank table and then update the state when it is updated. How do I update the table with a new row each time the 2 new values are added?
import React, { Component } from 'react';
import './App.css';
const table =
<table id="itemTable">
<tbody>
<tr><th>Title</th>
<th>Amount</th>
<th>Remove Item</th>
</tr>
</tbody>
</table>;
class App extends Component {
constructor(props){
super(props);
this.state = {
title: '',
amount: '',
table: {table}
};
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
//adds to table
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
render() {
return (
<section className="App">
<header>
<h1>Money Manager</h1>
</header>
<section>
<h1>Finances</h1>
<form>
<label htmlFor="name">Name</label>
<input type="text" name="title" onChange={this.handleChange}/>
<label htmlFor="amount">Amount</label>
<input type="text" name="amount" onChange={this.handleChange}/>
<button type="button" id="add" onClick={this.handleClick}>Add item</button>
</form>
<section>
<h1>Items</h1>
{table}
</section>
</section>
</section>
);
}
}
export default App

You should make the front of the table, and make a state for the content of the table, like this:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props){
super(props);
this.state = {
tableContent: []
};
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// Don't forget to check if the inputs are corrects
// Here i generate a random number for the key propriety that react need
let randomID = Math.floor(Math.random() * 999999);
// recreate a new object and stock the new line in
let newTab = this.state.tableContent;
newTab.push({
key: randomID,
title: "",
amount: "" // Don't forget to get the value of the inputs here
});
this.setState({
tableContent: newTab
});
// Clear the content of the inputs
// the state has changed, so the tab is updated.
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
render() {
return (
<section className="App">
<header>
<h1>Money Manager</h1>
</header>
<section>
<h1>Finances</h1>
<form>
<label htmlFor="name">Name</label>
<input type="text" name="title" onChange={this.handleChange}/>
<label htmlFor="amount">Amount</label>
<input type="text" name="amount" onChange={this.handleChange}/>
<button type="button" id="add" onClick={this.handleClick}>Add item</button>
</form>
<section>
<h1>Items</h1>
<table id="itemTable">
<thead>
<tr>
<th>Title</th>
<th>Amount</th>
<th>Remove Item</th>
</tr>
</thead>
<tbody>
{this.state.tableContent.map((item) =>
<tr key={item.key}>
<td>{item.title}</td>
<td>{item.amount}</td>
<td>
{/* Here add the onClick for the action "remove it" on the span */}
<span>Remove it</span>
</td>
<td></td>
</tr>
)}
</tbody>
</table>
</section>
</section>
</section>
);
}
}
export default App
It's not finished but i've commented what you should do and what i've done.

Related

In REACT When I try to update date using setState but it doesn't change date it always show current date but in console it shows the changed date

**import React, { Component } from 'react'
import moment from 'moment'
import {Form, Formik, Field, ErrorMessage} from 'formik'
import TodoDataService from '../../api/todo/TodoDataService'
import AuthenticationService from './AuthenticationService'
class TodoComponent extends Component {
constructor(props){
super(props)
this.state = {
id:this.props.params.id,
description:'',
targetDate: moment(new Date()).format('YYYY-MM-DD')
}
this.onSubmit = this.onSubmit.bind(this);
this.validate = this.validate.bind(this);
}
componentDidMount(){
let username = AuthenticationService.getLoginUserName()
TodoDataService.retrieveTodo(username, this.state.id)
.then(response => this.setState({
description: response.data.description,
targetDate: moment(response.data.targetDate).format('YYYY-MM-DD')
}))
}
validate(values){
let error = {}
if(!values.description){
error.description = "Enter a Description"
}
else if(values.description.length<5){
error.description = "Enter atleast 5 Characters in Description"
}
if(!moment(values.targetDate).isValid()){
error.targetDate="Enter a valid date"
}
return error
}
onSubmit(values){
let username = AuthenticationService.getLoginUserName()
let todo={
id: this.state.id,
description:values.description,
targetDate:values.targetDate
}
console.log(values)
if(this.state.id === -1){
TodoDataService.createTodo(username, todo)
.then(()=> this.props.navigate('/todos'))
}else{
TodoDataService.updateTodo(username, this.state.id,
todo).then(() => this.props.navigate('/todos'))
}
}
render() {
let {description, targetDate} = this.state;
return (
<div>
<h1>Update Todo Form </h1>
<div className="container">
<Formik initialValues = {{description, targetDate}} onSubmit={this.onSubmit}
validateOnChange={false} validateOnBlur={false} validate={this.validate} enableReinitialize={true}>
{
(props) =>(
<Form>
<ErrorMessage name="description" component="div" className="alert alert-warning"/>
<ErrorMessage name="targetDate" component="div" className="alert alert-warning"/>
<fieldset className="form-group">
<label>Description</label>
<Field className="form-control" type="text" name="description"/>
</fieldset>
<fieldset className="form-group">
<label>Target Date</label>
<Field className="form-control" type="date" name="targetDate"/>
</fieldset>
<button className="btn btn-success" type="submit" >Save</button>
</Form>
)
}
</Formik>
</div>
</div>
)
}
}
export default TodoComponent;**
import React, { Component } from 'react';
import TodoDataService from '../../api/todo/TodoDataService';
import AuthenticationService from './AuthenticationService';
import moment from 'moment';
class ListTodoComponent extends Component{
constructor(props){
super(props);
this.state={
todos:[],
message:null
}
this.deleteTodoClicked = this.deleteTodoClicked.bind(this);
this.refreshTodos = this.refreshTodos.bind(this);
this.updateTodoClicked = this.updateTodoClicked.bind(this);
this.addTobeClicked = this.addTobeClicked.bind(this);
}
componentDidMount(){
this.refreshTodos();
}
addTobeClicked(){
this.props.navigate(`/todos/-1`)
}
deleteTodoClicked(id){
let username = AuthenticationService.getLoginUserName()
TodoDataService.deleteTodo(username, id)
.then( response =>{
this.setState({message:`Delete of todo id ${id} Successfull`})
this.refreshTodos()
})
}
refreshTodos(){
let username = AuthenticationService.getLoginUserName()
TodoDataService.retrieveAllTodos(username)
.then(
response => {
this.setState({todos:response.data})
}
)
}
updateTodoClicked(id){
console.log("updated");
this.props.navigate(`/todos/${id}`)
}
render(){
return (
<div>
<div className="container">
<h1>List of Todos</h1>
{this.state.message &&<div className="alert alert-success">{this.state.message}</div>}
<table className="table">
<thead>
<tr>
<th>ID</th>
<th>Description</th>
<th>Is Completed?</th>
<th>Target Date</th>
<th>Delete</th>
<th>Update</th>
</tr>
</thead>
<tbody>
{
this.state.todos.map(
todo =>
<tr key={todo.id}>
<td>{todo.id}</td>
<td>{todo.description}</td>
<td>{String(todo.done)}</td>
<td>{moment(todo.targetDate).format('YYYY-MM-DD')}</td>
<td><button className="btn btn-warning" onClick={() => this.deleteTodoClicked(todo.id)}>Delete</button></td>
<td><button className="btn btn-success" onClick={() => this.updateTodoClicked(todo.id)}>Update</button></td>
</tr>
)
}
</tbody>
</table>
<div className="row">
<button className="btn btn-success" onClick={this.addTobeClicked}>Add Todo</button>
</div>
</div>
</div>
)
}
}
export default ListTodoComponent
When I try to add date but date remain same date but in console it shows the new added date why new added date don't show in screen.
When I try to add date but date remain same date but in console it shows the new added date why new added date don't show in screen.
When I try to add date but date remain same date but in console it shows the new added date why new added date don't show in screen.

Methods of matching string input with numerical input in ReactJS?

I am making a cooking app that adds up the total amount of ingredients for each recipe the user adds.
For example, the user adds "Cheese Burger" as the title and in that component it would have an input box to type in name of the ingredient then another input field for the amount of ingredients. At the end of the program I want to allow the user to click a button called "Add/Build Grocery list" at the end, but unsure how to match the different ingredients to the number value of that ingredient.
You mean something like this might help?
import React, { Component } from "react";
import "./styles.css";
class App extends Component {
state = {
Items: {},
CurItem: "",
Quantity: 0
};
render() {
return (
<div className="App">
<form
onSubmit={(e) => {
e.preventDefault();
const Items = { ...this.state.Items };
if (typeof Items[this.state.CurItem] === "undefined") {
Items[this.state.CurItem] = +this.state.Quantity;
} else {
Items[this.state.CurItem] += +this.state.Quantity;
}
this.setState({
Items,
CurItem: "",
Quantity: 0
});
}}
>
<label>
<strong>Item Name:</strong>
<input
type="text"
value={this.state.CurItem}
onChange={(e) => this.setState({ CurItem: e.target.value })}
/>
</label>
<label>
<strong>Quantity:</strong>
<input
type="number"
value={this.state.Quantity}
onChange={(e) => this.setState({ Quantity: e.target.value })}
/>
</label>
<input type="submit" />
</form>
<table border="1" width="50%">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{Object.keys(this.state.Items).map((item) => (
<tr>
<td>{item}</td>
<td>{this.state.Items[item]}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default App;
See demo here: https://j6fv7.csb.app/
Preview

How to access table cell data in react

I have created a cart using reactjs and now I pass an object into the cart and I can add quantity and then I will be calculated automatically subtotal of a product. But now I have to calculate Total using this subtotal value. So Can I know how to access table column 'subtotal' and calculate the total price of products purchased?
I have attached the table below.
render(){
const subtot =this.DrugsDetailsRequest.totalPrice*this.state.textInputValue1
console.log(subtot);// this will get you the total
const sum=sum+subtot;
console.log(sum);
return (
<tr>
<td data-th="Product">
<p>{this.DrugsDetailsRequest.item_name}</p>
</td>
<td> Rs: {this.DrugsDetailsRequest.totalPrice}</td>
<td>
<input name="textInputValue1" type="number" className="form-control text-center" onChange={ this.handleChange } />
</td>
<td className="text-center">
<input name="textInputValue2" type="text" className="form-control text-center" value={subtot}
onChange={ this.handleChange } />
</td>
<td className="actions">
<button className="btn btn-danger btn-sm" onClick={(e) => this.delete(this.DrugsDetailsRequest._id)}>Delete</button>
</td>
</tr>
);
}
}
enter image description here
This is one solution for you: Using Refs
For more information, you could read it here: Refs and the DOM
This is the example which looks closely to what you are in need.
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();
}
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
in react, you should try to make your UI rendering controled by the react's state.
in your case, if you want to access the subtotal, then you might design your component state like this:
class Cart extends React.Component {
constructor(props) {
super(props);
// initial cart state
this.state = {
total: 0,
inCartItems: {
ddd: {
price: 12,
quantity: 0,
subtotal: 0,
},
www: {
price: 45,
quantity: 0,
subtotal: 0,
},
e3400: {
price: 45,
quantity: 0,
subtotal: 0,
},
},
};
}
handleChange = (itemName, quantity) => {
// set new inCartItems state
// then use the updated state to calculate total by just sum up the subtotal in each items
}
render() {
return (
// your table content
<div>
{/*handle item number change like this*/}
<input onChange={(e) => this.handleChange('ddd', e.target.value)} />
<input onChange={(e) => this.handleChange('www', e.target.value)} />
<input onChange={(e) => this.handleChange('e3400', e.target.value)} />
<div className={'total'}>
{this.state.total}
</div>
</div>
// ....
);
}
}

React - How I can show submitted form records into another component in format of <li>?

I started learning React few weeks back and wanted to create small application. User will enter his details through form and his records will visible into table. But after record form fields details, I'm not able to show records into table, can someone help me.
I have 3 components ->
Main component = ShowFormRecords.jsx
Sub component = ShowTable.jsx
Sub component = ShowForm.jsx
In ShowForm.jsx I am able to record form fields value through this.onSubmit function in console.log(this.state);
Now how I can show recorded form details into another sub component ShowTable.jsx. I learned something about dynamic props can communicate one component to another component, but not able to implement here as per my requirement.
Component: ShowFormRecords.jsx
// Let's import React
import React from "react";
// Import custom component
import ShowTable from "./showformrecords/ShowTable.jsx";
import ShowForm from "./showformrecords/ShowForm.jsx";
// Let's create component [[ShowFormRecords]]
class ShowFormRecords extends React.Component{
render(){
return(
<div className="row">
<div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<h3> View Customer Records </h3>
</div>
<div className="col-12 col-sm-12 col-md-8 col-lg-8 col-xl-8">
<ShowTable />
</div>
<div className="col-12 col-sm-12 col-md-4 col-lg-4 col-xl-4">
<ShowForm />
</div>
</div>
);
}
}
// Let's render ReactDOM
export default ShowFormRecords;
ShowTable.jsx
// Let's import React
import React from "react";
// Let's create component [[ShowTable]]
class ShowTable extends React.Component{
render(){
return(
<div>
<table className="table table-responsive">
<thead className="thead-inverse">
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Phone No.</th>
<th>Issue</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"> <input type="checkbox" className="form-check-input" /> </th>
<td>Mark</td>
<td>Otto</td>
<td>0000000000</td>
<td>My pc is not working</td>
<td><button type="button" className="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
</div>
);
}
}
// Let's render ReactDOM
export default ShowTable;
ShowForm.jsx
// Let's import React
import React from "react";
// Let's create component [[ShowForm]]
class ShowForm extends React.Component{
// create constructor function for AddCustomer component - to init
constructor(props){
// call super, so constructor function can connect with AddCustomer component - to init super component
super(props);
// Use state add object with their property and value
this.state = {
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
}
// Creat custom change function
this.change = e =>{
this.setState({
[e.target.name]: e.target.value
});
};
this.onSubmit = e =>{
e.preventDefault();
console.log(this.state);
// clear form fields after click on submit button, use setState for setting value
this.setState({
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
})
}
} // close constructor function
render(){
return(
<form onSubmit={e => this.onSubmit(e)}>
<div className="form-group">
<label htmlFor="fname">First name</label>
<input
type="text"
className="form-control"
id="fname"
placeholder="First name"
name = "firstName"
value={this.state.firstName}
onChange = { e => this.change(e) }
// onChange={e => this.setState({firstName: e.target.value})}
/>
{/* call setState for change firstName value */}
</div>
<div className="form-group">
<label htmlFor="lname">Last name</label>
<input
type="text"
className="form-control"
id="lname"
placeholder="Last name"
name="lastName"
value={this.state.lastName}
onChange = { e => this.change(e) }
// onChange={e => this.setState({lastName: e.target.value})}
/>
{/* call setState for change lastName value */}
</div>
<div className="form-group">
<label htmlFor="phone">Phone no.</label>
<input
type="text"
className="form-control"
id="phone"
placeholder="Phone no."
name="phoneNo"
value={this.state.phoneNo}
onChange = { e => this.change(e) }
// onChange={e => this.setState({phoneNo: e.target.value})}
/>
{/* call setState for change phoneNo value */}
</div>
<div className="form-group">
<label htmlFor="issue">Issue</label>
<textarea
className="form-control"
id="issue"
rows="3"
name="issue"
value={this.state.issue}
onChange = { e => this.change(e) }
// onChange={e => this.setState({issue: e.target.value})}
>
{/* call setState for change issue value */}
</textarea>
</div>
<button type="submit" className="btn btn-primary"> Submit </button>
</form>
);
}
}
// Let's render ReactDOM
export default ShowForm;
Move your state from your ShowForm component up into your ShowFormRecords components. Then pass the state from the ShowFormRecords component into both your ShowTable and ShowForm component. By doing so, you can update your state in the ShowForm component then render that data on your ShowTable component.

I'm getting 'Uncaught TypeError: Cannot read property 'records' of undefined' when trying to re render my UI (using React.js and Rails)

I'm in the process of learning React and need some help with the handleSubmit event. I understand that when using setState it updates the components local state and triggers a refresh of the UI. but when attempting to push the new data to the props I get an error. "Uncaught TypeError: Cannot read property 'records' of undefined" I've read the docs over and over again along with several other articles and can't wrap my head around this. please help...
Here are my components: (All Records)
class Records extends React.Component {
constructor(props) {
super(props);
this.state = {
records: ''
}
this.handleNewRecord = this.handleNewRecord.bind(this);
}
componentDidMount() {
this.setState({
records: this.props.records
})
}
handleNewRecord(record) {
console.log(record);
const newRec = this.state.records.slice();
newRec.push(record);
this.setState({
records: newRec
})
}
render() {
const records = this.props.records.map((record) =>
<Record record={record} key={record.id} />
)
return (
<div className="container">
<h1>Records</h1>
<RecordForm handleNewRecord={this.handleNewRecord}/>
<table className="table">
<thead>
<tr>
<th>Date</th>
<th>Title</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{records}
</tbody>
</table>
</div>
)
}
}
(single record)
class Record extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<tr>
<td>{this.props.record.date}</td>
<td>{this.props.record.title}</td>
<td>{this.props.record.amount}</td>
</tr>
)
}
}
(record form)
class RecordForm extends React.Component {
constructor(props) {
super(props);
this.state = {
record: {
title: '',
amount: '',
date: ''
}
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
var key = e.target.name
var val = e.target.value
var obj = this.state.record
obj[key] = val
this.setState(obj)
}
handleSubmit(e) {
var that = this;
e.preventDefault();
$.ajax({
method: 'POST',
data: {
record: this.state.record,
},
url: '/records',
success: function(res) {
that.props.handleNewRecord(res)
},
})
console.log('submitted');
}
render () {
return (
<form className="form-inline" onSubmit={this.handleSubmit}>
<div className="form-group">
<label>
<input className="form-control" placeholder="date" type="text" name="date" value={this.state.record.date} onChange={this.handleChange} /><br />
</label>
<label>
<input className="form-control" placeholder="title" type="text" name="title" value={this.state.record.title} onChange={this.handleChange} /><br />
</label>
<label>
<input className="form-control" placeholder="amount" type="text" name="amount" value={this.state.record.amount} onChange={this.handleChange} /><br />
</label>
<label>
<button className="btn btn-primary" type="submit" value="submit" >Create Record</button><br />
</label>
</div>
</form>
);
}
}
In you code, the one thing you are missing is proper binding of the functions in your Records Component. In order to make your state available to a function you should bind it to the component's scope. Also when assigning props to the initial state is an anti-pattern and thus you should set you state variable to a prop in the componentDidMount function.
Another thing is that when you assign prop records to the state variable, you can use it from the state rather than prop in your map component.
Records
class Records extends React.Component {
constructor(props) {
super(props);
this.state = {
records: ''
}
}
componentDidMount() {
this.setState({records: this.props.records});
}
handleNewRecord = (record) => {
console.log(record);
const newRec = this.state.records.slice();
newRec.push(record);
this.setState({
records: records
})
}
render() {
const records = this.state.records.map((record) =>
<Record record={record} key={record.id} />
)
return (
<div className="container">
<h1>Records</h1>
<RecordForm handleNewRecord={this.handleNewRecord}/>
<table className="table">
<thead>
<tr>
<th>Date</th>
<th>Title</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{records}
</tbody>
</table>
</div>
)
}
}

Resources