0

So I can get the button through the event when it is clicked on. But when I do a filter, it does not remove the said button.

So I have my array in the constructor():

constructor()
{   
    super();
    this.options = [ 1, 2, 3, 4, 5]; 
    this.temp_option = []; 
    this.delete_me = this.delete_me.bind(this);
    this.buttons = [<button key="0" onClick={this.delete_me}/>,<button key="1" onClick={this.delete_me}/>];
    this.state = { buttons: this.buttons };
}

then I have the function:

delete_me(e)
{   
    console.log(e.target);
    this.buttons = this.buttons.filter((item) => item != e.target);
    console.log(this.buttons);
}

However this.buttons still has two elements in it.

I thought about another way to delete it and it was to use the 'key', but I can't seem to find anything about getting key value.

A. L
  • 11,695
  • 23
  • 85
  • 163

2 Answers2

4

The approach you are currently taking isn't really "react". You need to think more about a change in state rather than altering the dom directly.

One approach would be:

class App extends React.Component {
  constructor(){
    super();
    this.state ={
      visibleButtons: [ 11, 22, 33, 44 ],
      buttons: {
        11: {
          label: "Foo",
        },
        22: {
          label: "Bar"
        },
        33: {
          label: "Cow",
        },
        44: {
          label: "Pig"
        },        
      },
    }
  }

  onDelete(deletedId) {
    this.setState({
       visibleButtons: this.state.visibleButtons.filter(id => id !== deletedId)
    });
  }

  render () {                                        
    return (
      <div>
        { this.state.visibleButtons.map(buttonId => (
          <button key={buttonId} onClick={() => this.onDelete(buttonId)}>{this.state.buttons[buttonId].label}</button>
        )) }   
      </div>
    );
  }
}

ReactDOM.render(<App/>,document.getElementById('root'));

http://codepen.io/cjke/pen/RKwWwZ?editors=0010


Edit

An example showing adding and removing. The unique id is pretty primitive, and doesn't actively check for what is there, but you should get the gist:

class App extends React.Component {
  constructor(){
    super();
    this.onAdd = this.onAdd.bind(this);
    this.onChange = this.onChange.bind(this);

    this.state ={
      value: '',
      uniqueId: 100,
      visibleButtons: [ 11, 22, 33, 44 ],
      buttons: {
        11: {
          label: "Foo",
        },
        22: {
          label: "Bar"
        },
        33: {
          label: "Cow",
        },
        44: {
          label: "Pig"
        },        
      },
    }
  }

  onDelete(deletedId) {
    this.setState({
       visibleButtons: this.state.visibleButtons.filter(id => id !== deletedId)
    });
  }

  onChange(e) {
    this.setState({ value: e.target.value });
  }

  onAdd(e) {
    this.setState({
      uniqueId: this.state.uniqueId + 1,
      value: '',
      buttons: {
        ...this.state.buttons, 
        [this.state.uniqueId]: { 
          label: this.state.value,
        }
      },
      visibleButtons: [...this.state.visibleButtons, this.state.uniqueId],
    });
  }

  render () {                                        
    return (
      <div>
        <div>
        { this.state.visibleButtons.map(buttonId => (
          <button key={buttonId} onClick={() => this.onDelete(buttonId)}>{this.state.buttons[buttonId].label}</button>
        )) } 
        </div>
        <br/>
        <div>
          <input onChange={this.onChange} value={this.state.value}/><button onClick={this.onAdd}>+</button>
        </div>
      </div>
    );
  }
}

ReactDOM.render(<App/>,document.getElementById('root'));
Chris
  • 54,599
  • 30
  • 149
  • 186
  • Interesting answer, however I am doing this dynamically. I also have another button which can 'grow' the number of classes in the array. I was thinking along the lines of the id, but is there a way to access the 'key' attribute instead? – A. L Jan 03 '17 at 05:14
  • This *is* dynamic. You can easily easily add to it simply by pushing into the button array state – Chris Jan 03 '17 at 05:15
  • kind of wanted to avoid having to resort to ids since imo, it can get clunky. I used this logic in Angular 2 fine, and was just hoping I could transfer it over (could remove just using the button's `this`). But if this is the only way in react, then I'll give it a shot first. – A. L Jan 03 '17 at 05:17
  • I'm not sure which bit is missing though? How do you identify within the array without some sort of unique id? – Chris Jan 03 '17 at 05:19
  • In vanilla js, I think if you pass the button's `this` as in the button itself, you can match it to an array or something. I might be wrong as it was over a month ago that I attempted Angular 2. However, I'll give it a shot and see how it works out first. – A. L Jan 03 '17 at 05:20
  • That kind of sounds more like jquery. Here is a super simple example of adding and removing. Type in the box and hit + to add, click a button to delete: http://codepen.io/cjke/pen/ggOapv?editors=0010 – Chris Jan 03 '17 at 05:24
  • You're probably right on it being jquery... it can get quite confusing using all these libraries after a while lol. But I must mark Genaro Rocha's answer as the answer as it's more appropriate to the question. But your 'mapping' will probably help me in the future. – A. L Jan 03 '17 at 05:27
  • 1
    Thats cool. Be careful relying on internal properties such as _targetInst though. I don't mind which answer you accept but you should really try to embrace the react way when using react - it will make your life sooo much easier. – Chris Jan 03 '17 at 05:29
  • I'll try to keep the 'mapping' idea in mind and use it wherever appropriate. – A. L Jan 03 '17 at 05:36
  • Can I just ask why you use round brackets in your mapping? Is it just a person choice or is there an actual purpose? – A. L Jan 04 '17 at 00:17
  • 1
    In es6 if a function has only one statement, you can omit the return statement. So `const f = (a) => a + 2`. If that statement happens to occur over multiple lines, I use this form `const f = (a) => (a + 2)` as a) you can code collapse multiple lines, and b) the intention is clearer – Chris Jan 04 '17 at 01:15
1

First of all, you need to bind this to the scope of your callback function. If you want to access the react object instance used to render the button from the synthetic event, you can do so using the private variable _targetInst.

class Buttons extends React.Component{

  constructor(props) {
    super(props);
    this.delete_me = this.delete_me.bind(this);
        this.state = {
        buttons : [<button key="0" onClick={this.delete_me}>0</button>,<button key="1" onClick={this.delete_me}>1</button>]
    };
  }

  delete_me(e){
    const buttons = this.state.buttons.filter((button) => button != e._targetInst._currentElement);
    this.setState({ buttons });
  }   

  render() {
    return <div>{this.state.buttons}</div>;
  }
};

ReactDOM.render(
  <Buttons />,
  document.getElementById('container')
);

However, as Chris mentioned, your approach is not very much in line with the React patterns, and you should avoid accessing private methods or properties (usually named with an underscore)

Community
  • 1
  • 1
  • I have a similar question at http://stackoverflow.com/questions/41435474/using-filter-on-this-in-reactjs?noredirect=1#comment70077039_41435474 but it's in regard to a component itself, which is passed. This time there is no event. Do you think you could have a look? – A. L Jan 03 '17 at 05:30