Luksiuslukas2
Luksiuslukas2

Reputation: 89

Updating state with form inputs

Made a mess out of this one. The app opens a list with products and each product has an edit button, where you can change the information through inputs and then save that information with save button. But the state doesn't update itself and currently I can't type anything into the input field. I've been messing with this for several hours and checked React forms tutorial, but I'm still missing something. I've already got a form, which creates and inserts the product to the list and I've tried to copy it for product editing, but it didn't work. Thanks in advance, if you can spot the problem.

App code

import React from 'react';
import './App.css';
import ProductList from "../ProductList/ProductList";
import NewProd from "../NewProd/NewProd";
import ViewProd from "../ViewProd/ViewProd";
import EditProd from "../EditProd/EditProd";
import {BrowserRouter, Route} from "react-router-dom";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
            name: "", 
            ean: "", 
            type: "", 
            weight: "", 
            color: "", 
            active: false,
            products: [{name: "Cabbage", ean: "00000000", type: "Vegetable", weight: "2kg", color: "Green", active: false}, 
            {name: "Banana", ean: "111111111", type: "Fruit", weight: "0.3kg", color: "Yellow", active: false}, 
            {name: "Chocolate", ean: "22222222222", type: "Candy", weight: "0.2kg", color: "Brown", active: false}, 
            {name: "Orange", ean: "3333333333", type: "Fruit", weight: "0.5kg", color: "Orange", active: false}, 
            {name: "Cucumber", ean: "4444444444", type: "Vegetable", weight: "1kg", color: "Green", active: false}, ]
    };
};

handleFormSubmit = (e) => {
  e.preventDefault();
  let products = [...this.state.products];
  products.push({
      name: this.state.name,
      ean: this.state.ean,
      type: this.state.type,
      weight: this.state.weight,
      color: this.state.color,
      active: false,
  });
  this.setState({ products, 
    name: "", ean: "", type: "", weight: "", color: "", active: false}
  );
}
handleEditFormSubmit = (e) => {
  e.preventDefault();
  let products = [...this.state.products];
  products.splice(1, 1, {name: this.state.name,
    ean: this.state.ean,
    type: this.state.type,
    weight: this.state.weight,
    color: this.state.color,})
  this.setState({ products, name: "", ean: "", type: "", weight: "", color: ""}
  );
}

handleInputChange = (e) => {
    this.setState({...this.state,
    [e.target.name]: e.target.value})
  };

deleteProduct = (delIndex) => {
  let products = [...this.state.products].filter((product, index) => index !== delIndex);
  this.setState({ products });
};
isActive = () => {
  this.setState({active: !this.state.active})
}
setProductActive = (product, active) => {
  this.setState((state) => ({
    products: state.products.map(p => p.name === product.name ? { ...p, active } : p)
  }))
}

render() {
  return (
    <BrowserRouter>
    <div className="App">
      <ProductList products={this.state.products} 
      deleteProduct={this.deleteProduct}
      setProductActive={this.setProductActive} />
      <NewProd handleFormSubmit={this.handleFormSubmit}
      handleInputChange={this.handleInputChange}
      newName={this.state.name}
      newEan={this.state.ean}
      newType={this.state.type}
      newWeight={this.state.weight}
      newColor={this.state.color} />
      <Route path="/view" render={(props) => <ViewProd {...props} products={this.state.products} />} />
      <Route path="/edit" render={(props) => <EditProd {...props} products={this.state.products} 
      handleInputChange={this.handleInputChange}
      handleEditFormSubmit={this.handleEditFormSubmit}
      handleFormSubmit={this.handleFormSubmit}
      editName={this.state.name}
      editEan={this.state.ean}
      editType={this.state.type}
      editWeight={this.state.weight}
      editColor={this.state.color} />} />
    </div>
    </BrowserRouter>
  );
  }
}

export default App;

Edit Prod code

import React from "react";
import "./EditProd.css";
import {Link} from "react-router-dom";

class EditProd extends React.Component {
    render() { 
        const products = this.props.products;
        const index = this.props.location.state.prodIndex;
        return (
            <div>
                <h1>Edit Product</h1>
                <form onSubmit={this.props.handleEditFormSubmit} >
            <label htmlFor="name">Product Name: </label>
            <input id="editname" type="text" name="name" placeholder={products[index].name} value={this.props.editName} onChange={this.props.handleInputChange} />
            <label htmlFor="ean">EAN Code: </label>
            <input id="editean" type="text" name="ean" placeholder={products[index].ean} value={this.props.editEan} onChange={this.props.handleInputChange} />
            <label htmlFor="type">Product Type: </label>
            <input id="edittype" type="text" name="type" placeholder={products[index].type} value={this.props.editType} onChange={this.props.handleInputChange} />
            <label htmlFor="weight">Product Weight: </label>
            <input id="editweight" type="text" name="weight" placeholder={products[index].weight} value={this.props.editWeight} onChange={this.props.handleInputChange} />
            <label htmlFor="color">Product Color: </label>
            <input id="editcolor" type="text" name="color" placeholder={products[index].color} value={this.props.editColor} onChange={this.props.handleInputChange} />
            <button type="submit" value="Submit">Save</button>
            <Link to={{ pathname: "/"}} ><button>Close</button></Link>
        </form>
            </div>
        )
    }
};
export default EditProd;

Product List Code

import React from "react";
import "./ProductList.css";
import {Link} from "react-router-dom";

class ProductList extends React.Component {
    render() { 
        const products = this.props.products;
        return (
            <div>
                <h1>Product List</h1>
                <table>
                    <tr>
                        <th>Name</th>
                        <th>EAN Code</th>
                        <th>Type</th>
                        <th>Weight</th>
                        <th>Color</th>
                        <th>Active</th>
                    </tr>
                    {products.map((product, index) => {
                        return (
                            <tr key={index}>
                                <td>{product.name}</td>
                                <td>{product.ean}</td>
                                <td>{product.type}</td>
                                <td>{product.weight}</td>
                                <td>{product.color}</td>
                                <td><input type="checkbox" checked={product.active} onChange={(e) => this.props.setProductActive(product, e.target.checked)} /></td>
                                <td><Link to={{ pathname: "/view", state: { prodIndex: index }}} ><button>View</button></Link></td>
                                <td><Link to={{ pathname: "/edit", state: { prodIndex: index }}} ><button>Edit</button></Link></td>
                                <td><button onClick={() => this.props.deleteProduct(index)}>Delete</button></td>
                            </tr>
                        )
                    })}
                </table>
            </div>
        )
    }
}
export default ProductList;

New Product code

import React from "react";

class NewProd extends React.Component {
    render() {
        return (
            <div>
            <form onSubmit={this.props.handleFormSubmit}>
            <label htmlFor="name">Product Name: </label>
            <input id="name" type="text" name="name" value={this.props.newName} onChange={this.props.handleInputChange} />
            <label htmlFor="ean">EAN Code: </label>
            <input id="ean" type="text" name="ean" value={this.props.newEan} onChange={this.props.handleInputChange} />
            <label htmlFor="type">Product Type: </label>
            <input id="type" type="text" name="type" value={this.props.newType} onChange={this.props.handleInputChange} />
            <label htmlFor="weight">Product Weight: </label>
            <input id="weight" type="text" name="weight" value={this.props.newWeight} onChange={this.props.handleInputChange} />
            <label htmlFor="color">Product Color: </label>
            <input id="color" type="text" name="color" value={this.props.newColor} onChange={this.props.handleInputChange} />
            <button type="submit" value="Submit">Add New Product</button>
        </form>
        </div>
        )
    }
}
export default NewProd;

EDIT: As each product is an object in the array, would it be possible instead of updating the state, to remove the specific array object, based on the index, and replace it with the updated inputs?

Upvotes: 2

Views: 65

Answers (1)

Abdullah Abid
Abdullah Abid

Reputation: 1661

the issue is your using the name of the input to set the state variable but the names of the state variables are completely different from those in the inputs.There are no state variables called editName,editEan,editType,editWeight,editColor so you want to change that firstly

  <form onSubmit={this.props.handleEditFormSubmit}>
    <label htmlFor="name">Product Name: </label>
    <input id="editname" type="text" name="name" placeholder={products[index].name} value={this.props.editName} onChange={this.props.handleInputChange} />
    <label htmlFor="ean">EAN Code: </label>
    <input id="editean" type="text" name="ean" placeholder={products[index].ean} value={this.props.editEan} onChange={this.props.handleInputChange} />
    <label htmlFor="type">Product Type: </label>
    <input id="edittype" type="text" name="type" placeholder={products[index].type} value={this.props.editType} onChange={this.props.handleInputChange} />
    <label htmlFor="weight">Product Weight: </label>
    <input id="editweight" type="text" name="weight" placeholder={products[index].weight} value={this.props.editWeight} onChange={this.props.handleInputChange} />
    <label htmlFor="color">Product Color: </label>
    <input id="editcolor" type="text" name="color" placeholder={products[index].color} value={this.props.editColor} onChange={this.props.handleInputChange} />
    <button type="submit" value="Submit">Save</button>
    <Link to={{ pathname: "/"}} ><button>Close</button></Link>
</form>

Secondly you need to spread the state before setting a single item in the state

handleInputChange = (e) => {
  this.setState({...this.state,
     [e.target.name]: e.target.value})
  };

Upvotes: 1

Related Questions