I have two components Display.jsx and DisplayList.jsx. Components work together to display values from local storage. The problem is with DisplayList.JSX handleDelete() method loop.
I don't get it why it deletes first element instead of selected element? And how to fix that?
Github
Display.jsx
import {DisplayList} from './DisplayList';
class Display extends Component {
constructor(props){
let data = JSON.parse(localStorage.getItem('data'));
super(props)
this.state = {
data: data,
}
// Methods
this.displayValues = this.displayValues.bind(this);
}
displayValues(){
return this.state.data.map((data1, index) =>
<DisplayList
key = {index}
email = {data1.email}
password = {data1.password}
updateList = {this.updateList}
/>
)
}
// This is the method that will be called from the child component.
updateList = (data) => {
this.setState({
data
});
}
render() {
return (
<ul className="list-group">
{this.displayValues()}
</ul>
)
}
}
export default Display;
DisplayList.jsx
import React, { Component } from 'react'
import {Button, Modal, Form} from 'react-bootstrap';
export class DisplayList extends Component {
constructor(props){
super(props)
this.state = {
email: '',
password: '',
show: false,
};
// Methods
this.handleDelete = this.handleDelete.bind(this);
this.onChange = this.onChange.bind(this);
}
onChange(event){
this.setState({
[event.target.name]: event.target.value
})
};
handleDelete(){
const data = JSON.parse(localStorage.getItem('data'));
for (let index = 0; index < data.length; index++) {
if(this.props.email === data[index].email &&
this.props.password === data[index].password){
console.log(this.props.email);
console.log(data[index]);
data.splice(data[index], 1);
}
console.log('loop count');
}
localStorage.setItem('data', JSON.stringify(data));
this.props.updateList(data);
}
render() {
return (
<div className = "mt-4">
<li className="list-group-item text-justify">
Email: {this.props.email}
<br />
Password: {this.props.password}
<br />
<Button onClick = {this.handleShow} variant = "info mr-4 mt-1">Edit</Button>
<Button onClick = {this.handleDelete} variant = "danger mt-1">Delete</Button>
</li>
</div>
)
}
}
Instead of:
data.splice(data[index], 1);
Try rewriting entire array:
data = [
...data.slice(0, index),
...data.slice(index + 1)
];
handleDelete(){
const data = JSON.parse(localStorage.getItem('data'));
const filteredData = data.filter(
x => !(x.email === this.props.email && x.password === this.props.password)
);
localStorage.setItem('data', JSON.stringify(filteredData));
this.props.updateList(filteredData);
}
Related
I need help in my react code. I am displaying the list of checkbox items using api. My JSON file contains the data which is having IsAssigned True/False. If isAssigned is true for that item, item checkbox will be pre-checked on page load.
Now, I want to change the selection of Checkboxlist items. How can I get the id's of selected Checkboxes and call post/put api calls to make changes in the database.
There are checkboxes that are pre-selected isAssigned=true, unselect the pre-selected checkboxes isAssigned= false, select the checkboxes that are not pre-selected earlier.
Please find my react code and json data below. Also, help me out on achieving the above,
import React from "react";
export class SetDescItems extends React.Component {
static displayName = Assign_TemplateDescriptions.name;
constructor(props) {
super(props);
this.state = {
ProdDescrlist: [],
checkedItems: new Map(),
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
var isChecked = event.target.checked;
var item = event.target.value;
var id = event.target.id;
this.setState(prevState => ({ checkedItems: prevState.checkedItems.set(id, item, isChecked) }));
}
handleSubmit(event) {
event.preventDefault();
//Create an Array.
var checkedItems = new Array();
//Reference all the CheckBoxes
var chks = document.getElementsByTagName("INPUT");
// Loop and push the checked CheckBox id's in Array.
for (var i = 0; i < chks.length; i++) {
if (chks[i].checked) {
checkedItems.push(chks[i].id);
}
}
//Display the selected CheckBox id's.
if (checkedItems.length > 0) {
checkedItems = checkedItems.join(",");
console.log("Selected ids: " + checkedItems);
}
const data = checkedItems;
//write post api here
}
componentDidMount() {
this.getProdDescriptions();
}
async getProdDescriptions () {
const url = “/api/getDescriptions”;
await fetch(url)
.then(response => response.json())
.then((data) => {
this.setState({
ProdDescrlist: data,
loading: false
})
console.log(this.state.ProdDescrlist)
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit} >
<ul style={{ listStyle: 'none' }}>
{
(this.state.ProdDescrlist.map((item, index) => {
return (
<li key={index}>
<input type="checkbox"
id={item.ProdDescription_ID}
defaultChecked={item.isAssigned == "TRUE"?true:false}
value={item.DescriptionTextPlain}
onChange={this.handleChange} />
{item.DescriptionTextPlain}
</li>
)
}
))
}
</ul>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default SetDescItems;
[{"ProdDescription_ID":2863,"isAssigned":"TRUE","DisplaySequence":0,"DescriptionTextPlain":"A1Testig"},
{"ProdDescription_ID":2865,"isAssigned":"TRUE","DisplaySequence":0,"DescriptionTextPlain":"test"},
{"ProdDescription_ID":1778,"isAssigned":"FALSE","DisplaySequence":0,"DescriptionTextPlain":"Testing4"},
{"ProdDescription_ID":2864,"isAssigned":"FALSE","DisplaySequence":0,"DescriptionTextPlain":"A2 "},
{"ProdDescription_ID":1544,"isAssigned":"FALSE","DisplaySequence":5,"DescriptionTextPlain":"ProductGuide"},
{"ProdDescription_ID":1535,"isAssigned":"TRUE","DisplaySequence":10,"DescriptionTextPlain":"testexample"},
{"ProdDescription_ID":1536,"isAssigned":"FALSE","DisplaySequence":15,"DescriptionTextPlain":"Note"}]
You need to use checked prop in input tag
import "./styles.css";
import React from "react";
export class SetDescItems extends React.Component {
constructor(props) {
super(props);
this.state = {
ProdDescrlist: [],
checkedItems: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const id = parseInt(event.target.id, 10);
const index = this.state.checkedItems.indexOf(id);
const updatedArray = [...this.state.checkedItems];
if (index !== -1) {
updatedArray.splice(index, 1);
} else {
updatedArray.push(id);
}
this.setState((prevState) => ({
checkedItems: updatedArray
}));
}
handleSubmit(event) {
event.preventDefault();
let value = "";
this.state.checkedItems.forEach((item) => {
if (item) {
value = value === "" ? item : value + "," + item;
}
});
if (value !== "") {
alert(value);
}
}
componentDidMount() {
this.getProdDescriptions();
}
async getProdDescriptions() {
const url = "/api/getDescriptions";
await fetch(url)
.then((response) => response.json())
.then((data) => {
let items = data.reduce((acc, item) => {
if(item.isAssigned === "TRUE") acc.push(item.ProdDescription_ID);
return acc;
}, []);
this.setState({
ProdDescrlist: data,
loading: false,
checkedItems: items
});
});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<ul style={{ listStyle: "none" }}>
{this.state.ProdDescrlist.map((item, index) => {
return (
<li key={index}>
<input
type="checkbox"
id={item.ProdDescription_ID}
defaultChecked={item.isAssigned === "TRUE" ? true : false}
value={item.DescriptionTextPlain}
onChange={this.handleChange}
/>
{item.DescriptionTextPlain}
</li>
);
})}
</ul>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
I have no idea How to store the react js state into localstorage.
import React, { Component } from 'react'
import './App.css';
import { auth,createUserProfileDocument } from './firebase/firebase.utils'
import { TodoForm } from './components/TodoForm/TodoForm.component'
import {TodoList} from './components/TodoList/TodoList.component'
import {Footer} from './components/footer/footer.component'
import Header from '../src/components/header/header.component'
import {Redirect} from 'react-router-dom'
import {connect} from 'react-redux'
import {setCurrentUser} from './redux/user/user.actions'
export class App extends Component {
constructor(props) {
super(props)
this.input=React.createRef()
this.state = {
todos:[
{id:0, content:'Welcome Sir!',isCompleted:null},
]
}
}
todoDelete = (id) =>{
const todos = this.state.todos.filter(todo => {
return todo.id !== id
})
this.setState({
todos
})
}
toDoComplete = (id,isCompleted) =>{
console.log(isCompleted)
var todos = [...this.state.todos];
var index = todos.findIndex(obj => obj.id === id);
todos[index].isCompleted = !isCompleted;
this.setState({todos});
console.log(isCompleted)
}
addTODO = (todo) =>{
todo.id = Math.random()
todo.isCompleted = true
let todos = [...this.state.todos, todo]
this.setState({
todos
})
}
unsubscribeFromAuth = null;
componentDidMount() {
const { setCurrentUser } = this.props;
this.unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
userRef.onSnapshot(snapShot => {
setCurrentUser({
id: snapShot.id,
...snapShot.data()
});
});
}
setCurrentUser(userAuth);
});
}
componentWillUnmount() {
this.unsubscribeFromAuth();
}
render() {
return (
<div className='App'>
<Header />
<TodoForm addTODO={this.addTODO} />
<TodoList
todos={this.state.todos}
todoDelete={ this.todoDelete}
toDoComplete={ this.toDoComplete}
/>
<Footer/>
</div>
)
}
}
const mapStateToProps = ({ user }) => ({
currentUser: user.currentUser
});
const mapDispatchToProps = dispatch => ({
setCurrentUser: user => dispatch(setCurrentUser(user))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
in my input Form
import './TodoForm.style.css'
export class TodoForm extends Component {
constructor(props) {
super(props)
this.state = {
content : ''
}
}
handleChange = (e) =>{
this.setState({
content: e.target.value
})
}
handleSubmit =(e) =>{
e.preventDefault();
this.props.addTODO(this.state);
this.setState({
content: ''
})
}
render() {
return (
<div className='inputTask'>
<form onSubmit={ this.handleSubmit}>
<input
className="textBox"
type='text'
onChange={ this.handleChange}
value={this.state.content}
placeholder='what you want to do ...'
/>
</form>
</div>
)
}
}
export default TodoForm
I have no idea How to store the react js state into localstorage.
i searched on internet but unable to find the exact solution all the codes that i think is necessary post.
You can use reactLocalStorage to save any data in local storage
import {reactLocalStorage} from 'reactjs-localstorage';
reactLocalStorage.set('var', true);
reactLocalStorage.get('var', true);
reactLocalStorage.setObject('var', {'test': 'test'});
reactLocalStorage.getObject('var');
reactLocalStorage.remove('var');
reactLocalStorage.clear();
Read out the localStorage item in the componentDidMount callback. Simply read the item you want to get, check if it exists and parse it to a usable object, array or datatype that need. Then set the state with the results gotten from the storage.
And to store it, simply handle it in an event handler or helper method to update both the state and the localStorage item.
class ExampleComponent extends Component {
constructor() {
super();
this.state = {
something: {
foo: 'bar'
}
}
}
componentDidMount() {
const storedState = localStorage.getItem('state');
if (storedState !== null) {
const parsedState = JSON.parse(storedState);
this.setState({ something: parsedState });
}
}
clickHandler = (event) => {
const value = event.target.value;
const stringifiedValue = JSON.stringify(value);
localStorage.setItem('state', stringifiedValue);
this.setState({ something: value });
}
render() {
return (
<button onClick={clickHandler} value={this.state.something}>Click me</button>
);
}
}
Set data in localStorage
key-value pair :
localStorage.setItem('key_name',"value");
object
localStorage.setItem('key_name', JSON.stringify(object));
Remove data from localStorage
localStorage.removeItem('key_name');
Get data from localStorage
let data = localStorage.getItem('key_name');
object :
let data = JSON.parse(localStorage.getItem('key_name'));
clear localStorage (delete all data)
localStorage.clear();
I'm using react to create a panel to add a new product. I've created a separate auto-complete class which is supposed to render an input element and a list of suggested autofill items underneath. The input element shows but not the autofill suggestions. Have a look at the code
Autofill class
import React, { Component } from "react";
import firebase from "../Firebase";
export default class AutoCompleteDistID extends Component {
constructor() {
super();
this.state = {
sellerName: [],
sellerId: [],
suggestions: [],
};
}
componentDidMount() {
var sellerRef = firebase.database().ref().child("Sellers");
sellerRef.once("value", (snapshot) => {
snapshot.forEach((childSnap) => {
var distrName = childSnap.val().sellerName;
var distrId = childSnap.val().sellerName.sellerId;
// var distrName = [{ name: data.sellerName }];
this.setState((prevState) => {
return {
sellerName: [...prevState.sellerName, distrName],
sellerId: [...prevState.sellerId, distrId],
suggestions: [...prevState.suggestions, distrName],
};
});
});
});
}
onTextChange = (e) => {
var sellerNames = [this.state.sellerName];
const value = e.target.value;
let newSuggestions = [];
if (value.length > 0) {
const regex = new RegExp(`^${value}`, "i");
newSuggestions = sellerNames.sort().filter((v) => regex.test(v));
}
this.setState(() => ({ newSuggestions }));
};
renderSuggestions() {
const newSuggestions = this.state.suggestions;
if (newSuggestions.length === 0) {
return null;
}
return (
<ul>
{newSuggestions.map((item) => (
<li>{item}</li>
))}
</ul>
);
}
render() {
return (
<div>
<input onChange={this.onTextChange} />
{this.renderSuggestions}
</div>
);
}
}
Main form
import React, { Component } from "react";
import firebase from "../Firebase";
import AutoCompleteDistID from "./AutoCompleteDistID";
export default class Products extends Component {
constructor() {
super();
this.state = {
description: "",
prodQty: "",
};
this.pushProduct = this.pushProduct.bind(this);
}
handleFormChange = (event) => {
const target = event.target;
const colName = target.name;
this.setState({
[colName]: event.target.value,
});
};
pushProduct() {
const userRef = firebase.database().ref().child("Users"); //Get reference to Users DB
const prodData = this.state;
userRef.push(prodData);
}
render() {
return (
<div>
<br />
<form style={{ border: "solid", borderWidth: "1px", width: "600px" }}>
<br />
<input
type="text"
value={this.state.prodQty}
placeholder="Available Quantity"
onChange={this.handleFormChange}
name="prodQty"
/>
<input
type="text"
value={this.state.description}
placeholder="Description"
onChange={this.handleFormChange}
name="description"
/>
<AutoCompleteDistID />
<br />
<br />
</form>
<button onClick={this.pushProduct} type="button">
Add Product
</button>
<br />
</div>
);
}
}
State variable is suggestions but you are setting newSuggestions.
onTextChange = (e) => {
var sellerNames = [this.state.sellerName];
const value = e.target.value;
let newSuggestions = [];
if (value.length > 0) {
const regex = new RegExp(`^${value}`, "i");
newSuggestions = sellerNames.sort().filter((v) => regex.test(v));
}
// HERE IS THE MISTAKE
this.setState(() => ({ suggestions: newSuggestions }));
};
In AutoCompleteDistID render method
render() {
return (
<div>
<input onChange={this.onTextChange} />
{this.renderSuggestions()}
</div>
);
}
I have 2 components. Display and DisplayList. Components work together to display values from local storage. Everything works fine. However When I activate handleDelete method. Values are deleted from local storage but react doesn't re-render list.
Summary: I want for react to re render my displayValues after I activate method handleDelete()
Github Link
Display.JSX
import {DisplayList} from './DisplayList';
class Display extends Component {
constructor(props){
let data = JSON.parse(localStorage.getItem('data'));
super(props)
this.state = {
data: data,
}
// Methods
this.displayValues = this.displayValues.bind(this);
}
displayValues(){
return this.state.data.map((data1, index) =>
<DisplayList
key = {index}
email = {data1.email}
password = {data1.password}
/>
)
}
render() {
return (
<ul className="list-group">
{this.displayValues()}
</ul>
)
}
}
DisplayList.JSX
import {Button} from 'react-bootstrap';
export class DisplayList extends Component {
constructor(props){
super(props)
// Methods
this.handleDelete = this.handleDelete.bind(this);
}
handleDelete(){
const data = JSON.parse(localStorage.getItem('data'));
for (let index = 0; index < data.length; index++) {
if(this.props.email === data[index].email &&
this.props.password === data[index].password){
data.splice(data[index], 1);
}
}
localStorage.setItem('data', JSON.stringify(data));
}
render() {
return (
<div className = "mt-4">
<li className="list-group-item text-justify">
Email: {this.props.email}
<br />
Password: {this.props.password}
<br />
<Button variant = "info mr-4 mt-1">Edit</Button>
<Button onClick = {this.handleDelete} variant = "danger mt-1">Delete</Button>
</li>
</div>
)
}
}
One possible way you could achieve this is by sending down a callback function as a prop from Display.JSX to DisplayList.JSX. And from handleDelete, trigger the callback to the parent and set the state in it. Sample code follows.
Display.jsx
import {DisplayList} from './DisplayList';
class Display extends Component {
constructor(props){
let data = JSON.parse(localStorage.getItem('data'));
super(props)
this.state = {
data: data,
}
// Methods
this.displayValues = this.displayValues.bind(this);
}
displayValues(){
return this.state.data.map((data1, index) =>
<DisplayList
key = {index}
email = {data1.email}
password = {data1.password}
updateList = {this.updateList}
/>
)
}
// This is the method that will be called from the child component.
updateList = (data) => {
this.setState({
data
});
}
render() {
return (
<ul className="list-group">
{this.displayValues()}
</ul>
)
}
}
DisplayList.jsx
import {Button} from 'react-bootstrap';
export class DisplayList extends Component {
constructor(props){
super(props)
// Methods
this.handleDelete = this.handleDelete.bind(this);
}
handleDelete(){
const data = JSON.parse(localStorage.getItem('data'));
for (let index = 0; index < data.length; index++) {
if(this.props.email === data[index].email &&
this.props.password === data[index].password){
data.splice(data[index], 1);
}
}
localStorage.setItem('data', JSON.stringify(data));
this.props.updateList(data);
}
render() {
return (
<div className = "mt-4">
<li className="list-group-item text-justify">
Email: {this.props.email}
<br />
Password: {this.props.password}
<br />
<Button variant = "info mr-4 mt-1">Edit</Button>
<Button onClick = {this.handleDelete} variant = "danger mt-1">Delete</Button>
</li>
</div>
)
}
}
You can do like accepted answer and you can have other way to do this also, like below:
Moved your handleDelete event in Parent itself, where your state data is there.
class Display extends Component {
constructor(props){
let data = JSON.parse(localStorage.getItem('data'));
super(props)
this.state = {
data: data || [{email: 'j', password: "dsv" }],
}
}
handleDelete(email, password){
const data = JSON.parse(localStorage.getItem('data'));
data = data ? data : this.state.data
for (let index = 0; index < data.length; index++) {
if(email === data[index].email &&
password === data[index].password){
data.splice(data[index], 1);
}
}
localStorage.setItem('data', JSON.stringify(data));
this.setState({data});
}
render() {
console.log(this.state)
debugger
return (
<ul className="list-group">
{this.state.data.map((data1, index) =>
<DisplayList
key = {index}
email = {data1.email}
password = {data1.password}
handleDelete = {() => this.handleDelete(data1.email,data1.password )}
/>
)}
</ul>
)
}
}
and in DisplayList
export default class DisplayList extends Component {
constructor(props){
super(props)
}
render() {
return (
<div className = "mt-4">
<li className="list-group-item text-justify">
Email: {this.props.email}
<br />
Password: {this.props.password}
<br />
<Button variant = "info mr-4 mt-1">Edit</Button>
<Button onClick = {this.props.handleDelete} variant = "danger mt-1">Delete</Button>
</li>
</div>
)
}
}
Working Demo
Im having issues with react todo list.
When submitted the list item appears fine.
I should then be able to delete this be clicking on the item,however nothing happens. As soon as i try to add another item the pages refreshes and all items are removed?
console log just shows
[object object]
App
import React, { Component } from 'react';
import './App.css';
import TodoItem from './TodoItem';
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: []
};
this.addItems = this.addItems.bind(this);
this.deleteItem = this.deleteItem.bind(this);
}
addItems(e) {
if (this._inputElement !== '') {
let newItem = {
text: this._inputElement.value,
key: Date.now()
};
this.setState(prevState => {
return {
items: prevState.items.concat(newItem)
};
});
}
this._inputElement.value = '';
e.preventDefault();
}
deleteItem(key) {
console.log('key is' + key);
console.log('itesm as' + this.state.items);
var filteredItems = this.state.items.filter(function(item) {
return item.key !== key;
});
this.setState = {
items: filteredItems
};
}
render() {
return (
<div className="app">
<h2> things to do</h2>
<div className="form-inline">
<div className="header">
<form onSubmit={this.addItems}>
<input
ref={a => (this._inputElement = a)}
placeholder="enter task"
/>
<button type="submit">add</button>
</form>
</div>
</div>
<TodoItem entries={this.state.items} delete={this.deleteItem} />
</div>
);
}
}
export default App;
todoItem
import React, { Component } from 'react';
//search bar
class TodoItem extends Component {
constructor(props) {
super(props);
this.createTasks = this.createTasks.bind(this);
}
createTasks(item) {
return (
<li onClick={() => this.delete(item.key)} key={item.key}>
{item.text}
</li>
);
}
delete(key) {
console.log('key is ' + key);
this.props.delete(key);
}
render() {
let todoEntries = this.props.entries;
let listItems = todoEntries.map(this.createTasks);
return <ul className="theList">{listItems}</ul>;
}
}
export default TodoItem;
You are assigning to setState instead of using it as a method that it is
Change
this.setState = {
items: filteredItems
};
to
this.setState({
items: filteredItems
});
And that is also the reason it will reload the app, as you have overwritten the setState method you should be getting an error that setState is not a function and it would crash the app.