Sreekar Mouli
Sreekar Mouli

Reputation: 1442

Reactjs - Add, Delete from arrays dynamically

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

Answers (4)

Anji
Anji

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

Tholle
Tholle

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

Oleg Yakovlev
Oleg Yakovlev

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

Adnan
Adnan

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

Related Questions