2

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:

  • Restrict to create only fixed number of rules (say 4).
  • Delete a Rule by toggling the alert.

I tried to do the deletion in deleteRule function by trying to access event.target.value but it is undefined!!

4 Answers 4

2

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

Sign up to request clarification or add additional context in comments.

Comments

1

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).

Comments

1

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>
    );
  }
}

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.