Reputation: 411
I want to splice element from array in my todo app. As per code the first element is getting removed even if I click 2nd or 3rd remove button. Button used for removing element invokes remove(i) function,Here is my code for todo:
class App extends React.Component {
constructor(){
super();
this.state={
todo:[]
};
};
entertodo(keypress){
var Todo=this.refs.inputodo.value;
if( keypress.charCode == 13 )
{
this.setState({
todo: this.state.todo.concat({Value:Todo, Decor:'newtodo animated fadeInLeft', checked:false})
});
this.refs.inputodo.value=null;
};
};
todo(text,i){
return (
<li onClick={this.completes.bind(this,i)}className={text.Decor}>
<input type="checkbox" onChange={this.todoCompleted.bind(this,i)}className="option-input checkbox" checked={text.checked} />
<div key={text.id} className="item">
{text.Value}
<button type="button" className="destroy" onClick={this.remove.bind(this)}>X</button>
</div>
</li>
);
};
remove(i){
this.state.todo.splice(i,1)
this.setState({todo:this.state.todo})
};
todoCompleted(i){
var todo={...this.state.todo}
if(todo[i].checked){
this.state.todo[i].checked = false;
this.state.todo[i].Decor='newtodo'
this.setState({
todo: this.state.todo
});
}
else {
this.state.todo[i].checked = true;
this.state.todo[i].Decor= 'strike'
this.setState({
todo: this.state.todo
});
}
};
allDone= ()=>{
var todo = this.state.todo;
todo.forEach(function(item) {
item.Decor = "newtodo animated fadeInLeft strike"
})
this.setState({todo: todo});
};
completes(i){
var todo={...this.state.todo}
if(todo[i].Decor==='newtodo'){
this.state.todo[i].Decor='line'
this.setState({
todo: this.state.todo
});
}
else {
this.state.todo[i].Decor= 'newtodo'
this.setState({
todo: this.state.todo
});
}
};
render() {
return (
<div>
<h1 id='heading'>todos</h1>
<div className="lines"></div>
<div>
<input type="text" ref= "inputodo" onKeyPress={this.entertodo.bind(this)}className="inputodo"placeholder='todos'/>
<span onClick={this.allDone}id="all">x</span>
</div>
<div className="mainapp">
<ul>
{this.state.todo.map(this.todo.bind(this))}
</ul>
</div>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('app'));
.strike {
text-decoration: line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>
class App extends React.Component {
constructor(){
super();
this.state={
todo:[]
};
};
entertodo(keypress){
var Todo=this.refs.inputodo.value;
if( keypress.charCode == 13 )
{
this.setState({
todo: this.state.todo.concat({Value:Todo, Decor:'newtodo animated fadeInLeft', checked:false})
});
this.refs.inputodo.value=null;
};
};
todo(text,i){
return (
<li ocClick={this.completes.bind(this,i)}className={text.Decor}>
<input type="checkbox" onChange={this.todoCompleted.bind(this,i)}className="option-input checkbox" checked={text.checked} />
<div key={text.id} className="item">
{text.Value}
<button type="button" className="destroy" onClick={this.remove.bind(this)}>X</button>
</div>
</li>
);
};
remove(i){
this.state.todo.splice(i,1)
this.setState({todo:this.state.todo})
};
todoCompleted(i){
var todo={...this.state.todo}
if(todo[i].checked){
this.state.todo[i].checked = false;
this.state.todo[i].Decor='newtodo'
this.setState({
todo: this.state.todo
});
}
else {
this.state.todo[i].checked = true;
this.state.todo[i].Decor= 'strike'
this.setState({
todo: this.state.todo
});
}
};
allDone= ()=>{
var todo = this.state.todo;
todo.forEach(function(item) {
item.Decor = "newtodo animated fadeInLeft strike"
})
this.setState({todo: todo});
};
completes(i){
var todo={...this.state.todo}
if(todo[i].Decor==='newtodo'){
this.state.todo[i].Decor='line'
this.setState({
todo: this.state.todo
});
}
else {
this.state.todo[i].Decor= 'newtodo'
this.setState({
todo: this.state.todo
});
}
};
render() {
return (
<div>
<h1 id='heading'>todos</h1>
<div className="lines"></div>
<div>
<input type="text" ref= "inputodo" onKeyPress={this.entertodo.bind(this)}className="inputodo"placeholder='todos'/>
<span onClick={this.allDone}id="all">x</span>
</div>
<div className="mainapp">
<ul>
{this.state.todo.map(this.todo.bind(this))}
</ul>
</div>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('app'));
.strike {
text-decoration: line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>
Upvotes: 0
Views: 2290
Reputation: 19113
You forgot to pass the index to the bind()
for remove()
. Passing the index(i
) fixed this. Hope it helps!
class App extends React.Component {
constructor(){
super();
this.state={
todo:[],
finished: false,
};
};
entertodo(keypress){
var Todo=this.refs.inputodo.value;
if( keypress.charCode == 13 )
{
this.setState({
todo: this.state.todo.concat({Value:Todo, Decor:'newtodo animated fadeInLeft', checked:false})
});
this.refs.inputodo.value=null;
};
};
todo(text,i){
return (
<li ocClick={this.completes.bind(this,i)}className={text.Decor}>
<input type="checkbox" onChange={this.todoCompleted.bind(this,i)}className="option-input checkbox" checked={text.checked} />
<div key={text.id} className="item">
{text.Value}
<button type="button" className="destroy" onClick={this.remove.bind(this, i)}>X</button>
</div>
</li>
);
};
remove(i){
this.state.todo.splice(i,1)
this.setState({todo:this.state.todo})
};
todoCompleted(i){
var todo={...this.state.todo}
if(todo[i].checked){
this.state.todo[i].checked = false;
this.state.todo[i].Decor='newtodo'
this.setState({
todo: this.state.todo
});
}
else {
this.state.todo[i].checked = true;
this.state.todo[i].Decor= 'strike'
this.setState({
todo: this.state.todo
});
}
};
allDone= ()=>{
var todo = this.state.todo;
var _this = this
todo.forEach(function(item) {
item.Decor = _this.state.finished ? "newtodo animated fadeInLeft" : "newtodo animated fadeInLeft strike"
item.checked = !_this.state.finished
})
this.setState({todo: todo, finished: !this.state.finished});
};
completes(i){
var todo={...this.state.todo}
if(todo[i].Decor==='newtodo'){
this.state.todo[i].Decor='line'
this.setState({
todo: this.state.todo
});
}
else {
this.state.todo[i].Decor= 'newtodo'
this.setState({
todo: this.state.todo
});
}
};
render() {
return (
<div>
<h1 id='heading'>todos</h1>
<div className="lines"></div>
<div>
<input type="text" ref= "inputodo" onKeyPress={this.entertodo.bind(this)}className="inputodo"placeholder='todos'/>
<span onClick={this.allDone}id="all">x</span>
</div>
<div className="mainapp">
<ul>
{this.state.todo.map(this.todo.bind(this))}
</ul>
</div>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('app'));
.strike {
text-decoration: line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>
Upvotes: 1
Reputation: 2217
You are concatenating an array with an object.
this.state.todo.concat([{Value:Todo, Decor:'newtodo animated fadeInLeft', checked:false}])
You forget a space before your className
uses
onClick={this.completes.bind(this,i)} className={text.Decor}>
onChange={this.todoCompleted.bind(this,i)} className
In the remove function, don't use splice but concat/slice instead to avoid mutations
Upvotes: 0