Reputation: 1442
I have a component which takes input and adds them to a list and displays them:
import React, {Component} from 'react'
import {
Form,
Col,
Label,
FormGroup,
Button,
Alert,
Input,
Row,
} from 'reactstrap'
export default class NewSubreddit extends Component {
constructor(props) {
super(props)
this.state = {rules: []}
}
addRule() {
const rule = document.getElementById('new-rule').value
if(rule) {
this.setState(prev => ({
rules: prev.rules.concat(rule),
}))
}
console.log(this.state)
}
deleteRule(e) {
e.preventDefault()
console.log(e.target)
// this.setState(prev => ({
// }))
}
render() {
return (
<React.Fragment>
<Form>
<FormGroup row>
<Label sm={2}>Rules</Label>
<Col sm={10}>
<Row>
<Col>
<Input id='new-rule' type='text' placeholder='Add a rule that members of this community should follow!'/>
</Col>
<Col>
<Button onClick={() => this.addRule()}>ADD RULE</Button>
</Col>
</Row>
</Col>
</FormGroup>
<FormGroup row>
<Col>
{this.state.rules.map((rule) =>
<Alert key={rule} isOpen={true} toggle={this.deleteRule}>{rule}</Alert>
)}
</Col>
</FormGroup>
</Form>
</React.Fragment>
)
}
}
So, I am able to add the rules to the array rules
present in state
.
There are 2 things that I need to do here:
I tried to do the deletion in deleteRule
function by trying to access event.target.value
but it is undefined
!!
Upvotes: 2
Views: 4640
Reputation: 715
You are adding delete function to close button and it doesn't have any value. Either you need to add the click event for "Col" or else you can pass rule as a parameter.
<Col>
{this.state.rules.map((rule) =>
<Alert key={rule} isOpen={true} toggle={() => this.deleteRule(rule)}>{rule}</Alert>
)}
deleteRule(rule) {
console.log(rule);
// make a separate copy of the array
var array = [...this.state.rules];
var index = array.indexOf(rule);
array.splice(index, 1);
this.setState({rules: array});
}
I created a simple stack app with your code in stackblitz, please have a look.
https://stackblitz.com/edit/react-eqv744
Upvotes: 0
Reputation: 112927
You could create an inline function and pass in the index of the rule in the array to deleteRule
instead of the event and remove that rule from your state.
You could also hide the add button when you have 4 or more rules in your state.
Example
class NewSubreddit extends Component {
// ...
deleteRule(ruleIndex) {
this.setState(previousState => {
const rules = [...previousState.rules];
rules.splice(ruleIndex, 1);
return { rules };
});
}
render() {
return (
<React.Fragment>
<Form>
<FormGroup row>
<Label sm={2}>Rules</Label>
<Col sm={10}>
<Row>
<Col>
<Input
id="new-rule"
type="text"
placeholder="Add a rule that members of this community should follow!"
/>
</Col>
<Col>
{this.state.rules.length < 4 && (
<Button onClick={() => this.addRule()}>ADD RULE</Button>
)}
</Col>
</Row>
</Col>
</FormGroup>
<FormGroup row>
<Col>
{this.state.rules.map((rule, index) => (
<Alert
key={rule}
isOpen={true}
toggle={() => this.deleteRule(index)}
>
{rule}
</Alert>
))}
</Col>
</FormGroup>
</Form>
</React.Fragment>
);
}
}
Upvotes: 1
Reputation: 134
You can create some const with max number of rules and update your addRule function
in the constructor you can add
this.maxNumberOfRules = 4;
then update
addRule() {
const rule = document.getElementById('new-rule').value
if(!rule || this.state.rules.length === this.maxNumberOfRules) {
return null;
}
this.setState({rules: [...this.state.rules, rule]})
}
[...this.state.rules, rule] creates a new array with all items + new one. Then you can pass the rule or index of rule for deletion
{this.state.rules.map((rule, index) =>
<Alert key={rule} isOpen={true} toggle={(e) => this.deleteRule(e, index)}>{rule}</Alert>
)}
and change
deleteRule(e, indexForDelete) {
e.preventDefault()
console.log(index)
this.setState({rules: this.state.rules.filter((rule, ruleIndex) => ruleIndex !== indexForDelete)})
}
The filter() method creates an array filled with all array elements that pass a test (provided as a function).
Upvotes: 1
Reputation: 1707
You can delete the specific element by this method:
deleteRule = (idx) => () => {
this.setState({
rules: this
.state
.rules
.filter((s, sidx) => idx !== sidx)
});
}
You have to call function as:
<Col>
{this.state.rules.map((rule,idx) =>
<Alert key={rule} isOpen={true} toggle={this.deleteRule(idx)}>{rule}
</Alert>
)}
</Col>
Hope this help
Upvotes: 2