I have managed to create my function to select a single or multiple boxes. On the single ones I don't have any issue, I mean when you click a box it is checked or unchecked.
But it is not the same case with the select all. Any ideas how can I fix that? (I am using material-ui library for my boxes, but basically they are simple HTML input)
Select all component and function:
<Checkbox
name="checkboxes"
checked={this.state.allCheckboxes}
onChange={this.handleAllCheckboxes}
indeterminate
/>Select All
Function:
handleAllCheckboxes = (e) => {
let responseObj = this.state.items;
let prepareObj = {};
if(e.target.checked){
//to do add loop to check all check box
responseObj.forEach(function(item){
if(item.documentId !== null && item.documetNumber !== null ){
prepareObj[item.documentId] = item.documentNumber;
// this.refs.documentId
}
});
let toSee = Object.keys(prepareObj).length > 0 ? true : false;
this.setState({
docList: prepareObj,
visible: toSee
})
let checkboxes = document.getElementsByName('DocCheckbox')
checkboxes.forEach(function(checkbox){
checkbox.checked = checkbox.checked
})
console.log(checkboxes)
} else {
//to do add loop to uncheck all check box
this.setState({
prepareObj: {}
})
}
console.log(prepareObj);
};
Select single component and function:
<Checkbox
name='DocCheckbox'
type='checkbox'
color='default'
value={JSON.stringify({ documentId: rowData.documentId, documentNumber: rowData.documentNumber })}
onClick={this.handleCheckboxClick}/>
Function:
handleCheckboxClick = (e, id) => {
if (id) {
} else {
let parsedVal = JSON.parse(e.target.value);
// console.log(e.target.value)
let newDocList = { ...this.state.docList };
if (e.target.checked) {
this.setState({
singleCheckbox:true
})
newDocList[parsedVal.documentId] = parsedVal.documentNumber;
} else {
delete newDocList[parsedVal.documentId];
this.setState({
singleCheckbox:false
})
}
let toSee = Object.keys(newDocList).length > 0 ? true : false;
this.setState(
{
docList: newDocList,
visible: toSee
},
() => {
console.log(this.state.docList);
}
);
}
};
UPDATE
Answer of my code based to the reply of #norbitrial
( The answer is based on my properties , calls and data so feel free to modify it for your purpose )
Step 1 - Create a constructor to maintain your data and global checked state
constructor(props) {
super(props);
this.state = {
docList: {},
checked: false,
hasToCheckAll: false
}
}
Step 2 - Create functions to handle single and multiple checkboxes
Handle single checkbox
handleCheckboxClick = (clickedItem) => {
console.log(clickedItem)
// let parsedVal = JSON.parse(e.target.value);
let newDocList = { ...this.state.docList };
if (!clickedItem.checked) {
newDocList[clickedItem.documentId] = clickedItem.documentNumber;
console.log(newDocList)
} else {
delete newDocList[clickedItem.documentId];
}
let toSee = Object.keys(newDocList).length > 0 ? true : false;
console.log(toSee)
this.setState(
{
docList: newDocList,
visible: toSee
}, ()=>{
console.log(newDocList)
});
const updatedArray = this.state.items.map((item) => {
item.checked = item.documentId === clickedItem.documentId ? !item.checked : item.checked;
return item;
});
this.setState({
items: updatedArray,
});
};
Handle all checkboxes
handleAllCheckboxes = (e) => {
const hasToCheckAll = !this.state.hasToCheckAll;
const updatedArray = this.state.items.map((item) => {
item.checked = hasToCheckAll;
return item;
});
console.log(updatedArray)
let responseObj = this.state.items;
let prepareObj = {};
if (e.target.checked) {
//to do add loop to check all check box
responseObj.forEach(function (item) {
if (item.documentId !== null && item.documetNumber !== null) {
prepareObj[item.documentId] = item.documentNumber;
}
});
let toSee = Object.keys(prepareObj).length > 0 ? true : false;
console.log(toSee)
this.setState({
docList: prepareObj,
// allCheckboxes: true,
items: updatedArray,
hasToCheckAll,
visible: toSee
})
let checkboxes = document.getElementsByName('checkAll')
checkboxes.forEach(function (checkbox) {
checkbox.checked = e.target.checked
})
console.log(checkboxes)
} else {
console.log(updatedArray)
this.setState({
docList: {},
hasToCheckAll:false
})
}
};
Step 3 - Insert the state of the checked boxes inside into the object . And loop over them ( again this is coming from the response from my Back End so for everyone this step will be different )
.then((response) => {
// handle success
let dataItem = response.data.bills;
let prepareDataItem = [];
dataItem.forEach(function (item) {
item.checked = false;
prepareDataItem.push(item);
})
Step 4 - Render the checkboxes (these checkboxes are based on material-ui library , but it can work for a simple inputs also)
<Checkbox
name='DocCheckBox'
type='checkbox'
checked={rowData.checked}
color='default'
value={JSON.stringify({ documentId: rowData.documentId, documentNumber: rowData.documentNumber })}
onChange={() => this.handleCheckboxClick(rowData)}/>
<Checkbox
name="checkboxes"
checked={this.state.hasToCheckAll}
onChange={this.handleAllCheckboxes}
indeterminate
/>Select All
I would change a bit how you are handling these things in the application.
Technically you are manipulating the DOM directly, instead of leaving it to React with its states. In this case there is a definitely better way to handle checkbox states in the UI.
The solution:
1. Changed default state:
Let me state that I don't have the real data structure what you have so I have the following in the constructor just for the representation:
constructor(props:any) {
super(props);
this.state = {
items: [
{ documentId: 1, documentNumber: 1234, checked: false },
{ documentId: 2, documentNumber: 1235, checked: false },
{ documentId: 3, documentNumber: 1236, checked: false },
],
hasToCheckAll: false,
}
}
As you can see the items have checked property in order to handle them in the state.
2. Rendering the checkboxes differently
In the render function I have changed couple of things:
render() {
return (
<div>
<Checkbox
name="checkboxes"
checked={this.state.hasToCheckAll}
onChange={() => this.handleAllCheckboxes()}
indeterminate
/>Select All
{this.state.items.map((item:any) => {
return <div key={item.documentNumber}>
<Checkbox
name="DocCheckbox"
color="default"
checked={item.checked}
value={JSON.stringify({ ...item.documentId, ...item.documentNumber })}
onChange={() => this.handleCheckboxClick(item)}/> {item.documentNumber}
</div>
})}
</div>
)
}
3. Handling checkbox state is also changed:
Take a look at the following handlers:
handleAllCheckboxes = () => {
const hasToCheckAll = !this.state.hasToCheckAll;
const updatedArray = this.state.items.map((item:any) => {
item.checked = hasToCheckAll;
return item;
});
this.setState({
...this.state,
items: updatedArray,
hasToCheckAll: hasToCheckAll,
});
};
handleCheckboxClick = (clickedItem:any) => {
const updatedArray = this.state.items.map((item:any) => {
item.checked = item.documentId === clickedItem.documentId ? !item.checked : item.checked;
return item;
});
this.setState({
...this.state,
items: updatedArray,
});
};
The result:
Of course you can extend this example with your data manipulation if there is a further need. The solution has been built with TypeScript - I had a project opened with that - but you can remove types where it has been added.
The above example works like charm, I hope this helps!
Related
Panel is a datamodel fetched from database. avialablePanels is a dropdown where I can select an option I want. PanelCode dropdown is populated using a lookup table because it acts as a form where the displayed value is what Panel['PanelCode'] has and other values with which I can update. When I update a value of Panel[PanelCode] with the help of indexing using the PanelCode dropdown form it initially updates the value in the Panel['PanelCode'] array. Now lets say I want to update another value in the Panel['PanelCode'] and save them together as soon as I select another option from avialablePanels the first updated value of Panel['PanelCode'] is lost.
Panel: {
PanelCode: [ 1, 4 ]
}
availablePanels:[
{ OptionCode: 'R1-1', OptionKey: 1, OptionValue: 'Stop' },
{ OptionCode: 'R1-3P',OptionKey: 4,OptionValue: 'All Way (plaque)'}
]
export default class PanelTest extends Component {
constructor(props) {
super(props);
console.log(this.props.pointModel)
this.state = {...this.props.pointModel,
availablePanels:[],
selectedIndex: 0,
selectedPanel: null,
tempPanelCode: this.props.pointModel.Panel.PanelCode[0]===null?0:
this.props.pointModel.Panel.PanelCode[0],
}
}
render() {
return(
<Container>
{this.state.availablePanels.length>0 &&
<PtSelect label="Available Panel"
options={this.state.availablePanels}
name="selectedPanel" defaultVal={this.state.selectedPanel}
onChange={this.onChangeSelectedPanelDropdown} />}
{this.renderPanelinfo()}
</Container>
)
}
onChangeSelectedPanelDropdown = (e) => {
const { target } = e;
const {name, value} = target;
let indexVal = this.state.Panel.PanelCode.indexOf(parseInt(value))
this.setState({ [name]: parseInt(value),
selectedIndex:indexVal,
tempPanelCode: this.props.pointModel.Panel.PanelCode[indexVal]===null?0:
this.props.pointModel.Panel.PanelCode[indexVal]
});
}
renderPanelinfo = () =>{
const {typeOptions} = DropdownLib.getSignNum().Signs_Types;
/* typeOptions looks like availablePanels but with more options */
return (
<div>
<PtSelect label="Panel Code" options={typeOptions}
disabled={this.props.disabled}
name="PanelCode" defaultVal={this.state.tempPanelCode}
onChange={this.onChangeDropdown} />
</div>
)
}
getAvaialablePanels=()=>{
const availablePanelOptions = []
const optionKey = []
//const optionvalue = []
fetch(`${config.server}/getavailablepanels/`+this.state.Support.SignId)
.then(response=>
{
return response.json();
})
.then(data=>{
for (var i =0;i<data.length;i++){
availablePanelOptions.push(data[i]['OptionCode'])
optionKey.push(data[i]['OptionKey'])
//optionvalue.push(data[i]['OptionValue'])
}
let dropOptions = availablePanelOptions.map((option,idx)=>{
return {key:optionKey[idx],value: optionKey[idx], label:option}
});
this.setState({
availablePanels:dropOptions
});
})
.catch(error=>{
console.log(error);
});
}
onChangeDropdown = (e) => {
const { target } = e;
const {name, value} = target;
this.props.triggerNeedSave();
// eslint-disable-next-line
let stateVariable = 'temp'+[name]
this.setState({
[stateVariable]: parseInt(value)
});
this.props.pointModel.Panel[name][this.state.selectedIndex] = parseInt(value);
console.log(this.state)
}
componentDidMount(){
this.getAvaialablePanels()
}
}
Any help is really appreciated.
I don't understand why below code doesn't change state. Even when 'if' statement is executed, state is the same. Why case with if doesn't change state?
class Welcome extends React.Component {
state = {
items: [
{
id: 1,
done: false,
},
{
id: 2,
done: false,
},
{
id: 3,
done: false,
},
]
}
handleDone = (index) => {
this.setState((prevState) => {
const copyItems = [...prevState.items];
if (copyItems[index].done === false) {
console.log("Done should be true");
copyItems[index].done = true;
} else {
console.log("Done should be false");
copyItems[index].done = false;
}
// copyItems[index].done = !copyItems[index].done - the same result
return {
items: [...copyItems],
};
});
}
render() {
return (
this.state.items.map((item, index) => {
return (
<div>
<span>id: {item.id}</span>
<span> {item.done ? "- is not done" : "- is done"} </span>
<button
onClick={() => this.handleDone(index)}>
Change to opposite
</button>
</div>
)
})
)
}
}
ReactDOM.render(<Welcome />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
this.setState((prevState) => {
const copyItems = [...prevState.items];
if (copyItems[index].done === false) {
console.log("Done should be true");
copyItems[index].done = true;
} else {
console.log("Done should be false");
copyItems[index].done = false;
}
// copyItems[index].done = !copyItems[index].done - the same result
return {
items: [...copyItems],
};
});
Below example works fine when there is no if statement:
this.setState((prevState) => {
const copyItems = [...prevState.items];
copyItems[index].done = true;
return {
items: [...copyItems],
};
});
Below example works fine with 'if' statement in case when object is copied:
this.setState((prevState) => {
const copyItems = JSON.parse(JSON.stringify([...prevState.items]));
copyItems[index].done = !copyItems[index].done
return {
items: [...copyItems],
};
});
What's wrong for React is that even if you spread your array, the object inside it are still referenced as the object inside your state. So by doing copyItems[index].done = true; you're actually mutating the state directly (this.state[index].done should be true also). What you can do to avoid this is to use .map on your prevState so you're not updating the state directly.
const state = [{ done: true }];
const stateCopy = [...state];
const toFind = 0;
stateCopy[toFind].done = false;
console.log(stateCopy[toFind], state[toFind]); // { done: false } , { done: false } /!\ state should not be updated at this point.
// good way of doing that might be by using prevState.items.map() and do your logic inside it
const stateUpdated = state.map((el, index) => {
if (index === toFind) {
return { done: !el.done }
}
return el;
});
console.log(stateUpdated[toFind], state[toFind]) // state is not mutated, as expected
Problem was caused by create-react-app that wrap app with <React.StrictMode>.
To resolve it just remove this wrapping tag. And that's it.
It's expected behaviour and it should help avoid bugs on prod. More details in React docs.
I am referring to this tutorial for simple react autocomplete https://www.digitalocean.com/community/tutorials/react-react-autocomplete
But I have a slightly different requirement. Instead of typing something on the input field, I want all the suggestions to come up on clicking the input field. I am basically implementing a requirement where on clicking the input field, it should show user what are the available options.
Here is my sandbox https://codesandbox.io/s/distracted-easley-wdm5x
Specifically in the Autocomplete.jsx file (as mentioned below)
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
class Autocomplete extends Component {
static propTypes = {
suggestions: PropTypes.instanceOf(Array)
};
static defaultProps = {
suggestions: []
};
constructor(props) {
super(props);
this.state = {
// The active selection's index
activeSuggestion: 0,
// The suggestions that match the user's input
filteredSuggestions: [],
// Whether or not the suggestion list is shown
showSuggestions: false,
// What the user has entered
userInput: ""
};
}
onChange = (e) => {
const { suggestions } = this.props;
const userInput = e.currentTarget.value;
// Filter our suggestions that don't contain the user's input
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
);
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.value
});
};
onClick = (e) => {
this.setState({
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: e.currentTarget.innerText
});
};
onClick2 = (e) => {
console.log("text check", e.currentTarget.innerText);
if (e.currentTarget.innerText === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.innerText
});
}
};
onKeyDown = (e) => {
const { activeSuggestion, filteredSuggestions } = this.state;
// User pressed the enter key
if (e.keyCode === 13) {
this.setState({
activeSuggestion: 0,
showSuggestions: false,
userInput: filteredSuggestions[activeSuggestion]
});
}
// User pressed the up arrow
else if (e.keyCode === 38) {
if (activeSuggestion === 0) {
return;
}
this.setState({ activeSuggestion: activeSuggestion - 1 });
}
// User pressed the down arrow
else if (e.keyCode === 40) {
if (activeSuggestion - 1 === filteredSuggestions.length) {
return;
}
this.setState({ activeSuggestion: activeSuggestion + 1 });
}
};
render() {
const {
onChange,
onClick2,
onClick,
onKeyDown,
state: {
activeSuggestion,
filteredSuggestions,
showSuggestions,
userInput
}
} = this;
let suggestionsListComponent;
if (showSuggestions) {
if (filteredSuggestions.length) {
suggestionsListComponent = (
<ul className="suggestions">
{filteredSuggestions.map((suggestion, index) => {
let className;
// Flag the active suggestion with a class
if (index === activeSuggestion) {
className = "suggestion-active";
}
return (
<li className={className} key={suggestion} onClick={onClick}>
{suggestion}
</li>
);
})}
</ul>
);
} else {
suggestionsListComponent = (
<div className="no-suggestions">
<em>No suggestions, you're on your own!</em>
</div>
);
}
}
return (
<Fragment>
<input
type="text"
onChange={onChange}
onKeyDown={onKeyDown}
value={userInput}
onClick={onClick2}
/>
{suggestionsListComponent}
</Fragment>
);
}
}
export default Autocomplete;
In the input element in return section,
<input
type="text"
onChange={onChange}
onKeyDown={onKeyDown}
value={userInput}
onClick={onClick2}
/>
I have added a onClick functionality that calls the function onClick2.
onClick2 = (e) => {
console.log("text check", e.currentTarget.innerText);
if (e.currentTarget.innerText === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.innerText
});
}
};
My function simply returns all the suggestions back on clicking the input field. I am able to select items from suggestions and it gets put in the input field. But when I click on the input field again, the value disappears.
I want this autocomplete suggestion to only show once on clicking the empty input field and after selecting the item from list, I should be able to edit the value further.
What am I doing wrong?
Input values are not stored into innerText, but in value prop.
Look at this:
onClick2 = (e) => {
console.log("text check", e.currentTarget.innerText);
if (e.currentTarget.value === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.value
});
}
};
This should solve your problem
You are doing the wrong check in onClick2 function. Instead of checking e.currentTarget.innerText === "", it has to be e.target.value as we are validating the text in input field.
onClick2 = (e) => {
console.log("text check", e.target.value);
if (e.target.value === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.innerText
});
}
};
Here is the working link - https://codesandbox.io/s/jolly-meadow-5fr6x?file=/src/Autocomplete.jsx:1344-1711
I'm having an issue where upon loading the page I can either sort the table by the "name" column (ascending or descending) - - OR - - use a searchbar to filter through the names of the employees. My issue is that once I've sorted alphabetically, the search/filter no longer works.
I'm very new to React (I'm sure that's very obvious by my code) so please let me know if there's something obvious I'm doing wrong. Thanks in advance!
import React, { Component } from "react";
import API from "../utils/API"
import EmployeeRow from "./EmployeeRow"
class TableMain extends Component {
state = {
result: [],
search: "",
sortOrder: "descending"
}
componentDidMount() {
API.search()
.then(results => {
console.log(results)
this.setState({
result: results.data.results.map((res, i) => ({
image: res.picture.large,
firstName: res.name.first,
lastName: res.name.last,
phone: res.phone,
email: res.email,
dob: res.dob.date,
key: i
})
)
})
})
};
filterResults = (results) => {
const value = this.state.search
const finalResult = results.filter((employee) => {
const lastName = employee.lastName.toLowerCase();
const firstName = employee.firstName.toLowerCase()
const fullName = firstName + " " + lastName
if (fullName.includes(value)) {
return employee
}
});
return finalResult
};
sortResults = (event) => {
const results = this.state.result
// const id = event.target.id
// if (id === 'name'){
// } else if (id === 'phone'){
// } else if (id === 'email'){
// }
if (this.state.sortOrder === "descending") {
results.sort((a, b) => {
if (a.firstName > b.firstName) {
return -1
}
return a.firstName > b.firstName ? 1 : 0
},
this.setState({ sortOrder: "ascending" }))
} else if (this.state.sortOrder === "ascending") {
results.sort((a, b) => {
if (a.firstName < b.firstName) {
return -1
}
return a.firstName > b.firstName ? 1 : 0
},
this.setState({ sortOrder: "descending" }))
}
console.log("RESULTS: ", results)
this.setState({
sortedResults: results,
isSorted: true
})
}
onChange = e => {
const value = e.target.value;
if (!value) {
this.setState({ isSearchEmpty: true });
} else {
this.setState({ search: e.target.value, isSearchEmpty: false });
}
}
render() {
// console.log("State", this.state)
let employeeResults = this.state.result
if (this.state.isSearchEmpty) {
employeeResults = this.state.result
} else {
employeeResults = this.filterResults(this.state.result)
}
if (this.state.isSorted) {
employeeResults = this.state.sortedResults
}
return (
<div>
<input label="Search" onChange={this.onChange} />
<div className="row">
<table style={{ width: "100%" }}>
<tbody>
<tr>
<th>Image</th>
<th style={{ cursor: "pointer" }} onClick={this.sortResults} id="name">Name</th>
<th id="phone">Phone</th>
<th id="email">Email</th>
<th id="dob">DOB</th>
</tr>
{[...employeeResults].map((item) =>
<EmployeeRow
image={item.image}
firstName={item.firstName}
lastName={item.lastName}
email={item.email}
phone={item.phone}
dob={item.dob}
key={item.key}
/>
)}
</tbody>
</table>
</div>
</div>
)}
}
export default TableMain;
The issue is:
if (this.state.isSorted) {
employeeResults = this.state.sortedResults;
}
When you sort, you set state.isSorted to true, however you never set it back to false once you have finished. When you then try to filter, you do the filter:
if (this.state.isSearchEmpty) {
employeeResults = this.state.result;
} else {
employeeResults = this.filterResults(this.state.result);
}
if (this.state.isSorted) { // this is never reset after sorting.
employeeResults = this.state.sortedResults;
}
But as this.state.isSorted is still true, you use the values in this.state.sortedResults again.
please let me know if there's something obvious I'm doing wrong
You are making this tricky for yourself, as you are filtering/sorting the same collection of data. That's why you need to perform the action in the render, as you are trying to maintain the original list for later usage.
If you seperate the list into two collections: original unmodified and a display list, you can always refer to the original list to perform filtering/sorting.
componentDidMount() {
API.search().then(results => {
const tableData = results.data.results.map((res, i) => ({
image: res.picture.large,
firstName: res.name.first,
lastName: res.name.last,
phone: res.phone,
email: res.email,
dob: res.dob.date,
key: i
}));
this.setState({ originalResults: tableData, displayResults: tableData });
});
}
Then filtering can be done, as soon as the onChange occurs:
onChange = e => {
const query = e.target.value;
this.setState(prevState => ({
displayResults:
query.length > 0
? this.filterResults(query, prevState.originalResults)
: prevState.originalResults
}));
};
and similarly for the sorting, which can be performed on the display-results rather than the whole which means you can now sort, filtered results.
I created an example here https://codesandbox.io/s/sad-cannon-d61z6
I stubbed out all the missing functionality.
I started to learn React and I try to make a To do list. I stuck at editing items from the list. This is how I see this. To edit single item I click on the "edit" button, input appears in the place of the item, I submit changes by hiting the "enter" button.
My problem is
my function for submit button don't work (handleEditingDone - in the code).
when I click on the "edit" button TypeError appears
Cannot read property 'task' of undefined
(handleEditing in the code)
App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
// task: '',
// id: '',
//completed: false,
// all of our to-dos
],
todo: '',
// an empty string to hold an individual to-do
filtertodos: []
}
}
inputChangeHandler = event => {
this.setState({[event.target.name]: event.target.value})
}
addTask = event => {
event.preventDefault();
let newTask = {
task: this.state.todo,
id: Date.now(),
completed: false,
editing: false
};
this.setState({
todos: [...this.state.todos, newTask],
todo: ''
})
}
handleEditing = (id) => {
const todos = this.state.todos.map(todo => {
if (todo.id === id) {
todo.editing = !todo.editing
}
return todo
});
this.setState({
todos : todos,
todo: {
changedText: this.todo.task,
}
})
}
handleEditingDone = event => {
if (event.keyCode === 13) {
this.setState(prevState => ({
todo: { // object that we want to update
editing: false, // update the value of specific key
}
}));
}
}
handleEditingChange = event => {
let _changedText = event.target.value;
this.setState({
todo: {changedText: _changedText}
});
}
componentDidMount() {
this.setState({
todo: {changedText: this.todo.task}
})
}
Todo.js
const Todo = props => {
return (
<div style={{display: "flex"}}>
{props.todo.editing ? (
<input onKeyDown={event => props.handleEditingDone} onChange={event => props.handleEditingChange}
type="text" value={props.changedText}/> )
:
(<p key={props.todo.id}
onClick={event => {
props.toggleComplete(props.todo.id)
}} >{props.todo.changedText}{props.todo.completed && ' Completed'}</p>)
}
<button onClick={event => props.handleEditing(props.todo.id)}>EDIT</button>
<button onClick={event => {
props.onDelete(props.todo.id)
}}>x
</button>
</div>
)
}
The problem is the following:
this.todo.task
There is no this.todo.
Try
this.state.todo