4

Actually, I've been trying to add a 'Delete a comment' functionality to my Comment Box system.

Here is my code:-

var Comment = React.createClass({
  handleClick: function(e){
    e.preventDefault();
    var commentId = this.props.comment.id;
    return this.props.onDelete(commentId);
  },
  render: function () {
    return (
      <div className="comment">
        <h4 className="commentAuthor">
          {this.props.comment.email}
        </h4>
          {this.props.comment.comment}
          <a onClick={this.handleClick}> &times; </a>
      </div>
      );
  }
});

var CommentList = React.createClass({
  handleDelete: function(commentId){
    return this.props.del(commentId);
  },
  render: function () {
    var commentNodes = this.props.comments.map(function (comment, index) {
      return (
        <Comment comment = {comment} onDelete = {this.handleDelete} key = {index} />
        );
    });

    return (
      <div className="commentList">
        {commentNodes}
      </div>
      );
  }
});

var CommentBox = React.createClass({
  getInitialState: function () {
    return {comments: []};
  },
  componentDidMount: function () {
    this.loadCommentsFromServer();
  },
  loadCommentsFromServer: function () {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      success: function (comments) {
        this.setState({comments: comments});
      }.bind(this),
      error: function (xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  handleCommentSubmit: function(comment) {
    var comments = this.state.comments;
    var newComments = comments.concat([comment]);
    this.setState({comments: newComments});
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      type: 'POST',
      data: {"comment": comment},
      success: function(data) {
        this.loadCommentsFromServer();
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  delc: function(commentId){
    $.ajax({
      url: this.props.url,
      data: {"id" : commentId},
      type: 'DELETE',
      dataType: 'json',
      success: function (comments) {
        this.setState({comments: comments});
      }.bind(this), 
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
      });
  },
  render: function () {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList del={this.delc} comments={this.state.comments} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit}/>
      </div>
      );
  }
});

var CommentForm = React.createClass({
  handleSubmit: function() {
    var email = this.refs.email.getDOMNode().value.trim();
    var comment = this.refs.comment.getDOMNode().value.trim();
    this.props.onCommentSubmit({email: email, comment: comment});
    this.refs.email.getDOMNode().value = '';
    this.refs.comment.getDOMNode().value = '';
    return false;
  },

  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="email" placeholder="Your email" ref="email" />
        <input type="text" placeholder="Say something..." ref="comment" />
        <input type="submit" value="Post" />
      </form>
      );
  }
});

var ready = function () {
  React.renderComponent(
    <CommentBox url="18/comments.json" />,
    document.getElementById('art')
  );
};

$(document).ready(ready);

Now, when I try to delete a comment, it throws an error that says 'Uncaught TypeError: undefined is not a function'

Switching to 'source' tab on devTool, I found that the problem is in 'onDelete' function.

It says, 'onDelete' function is undefined.

I think the problem is due to 'this' keyword, but I'm not sure.

What should I do to resolve this issue? Let me know if I'm missing out on something.(I'm a newbie)

Thank you in advance.

bdj_
  • 43
  • 2
  • 7
  • 1
    You're not binding the function passed to this.props.comments.map. – Brigand Nov 07 '14 at 18:48
  • I think I got it. Initailizing: 'var that = this;' and then 'onDelete = {that.handleDelete}' should work? – bdj_ Nov 07 '14 at 18:59
  • 4
    Yes, or you can do `.map(function(comment, index){ ... }.bind(this))` or `.map(function(comment, index){ ... }, this)` – Brigand Nov 07 '14 at 22:39
  • 1
    aha, It worked! Thank you so much, Sir! :) One more question, now I ran into another problem. Could you please check my 'delc' function to see if there is something wrong with it? As I try to delete, It says, "DELETE http://localhost:3000/18/comments 404 (Not Found) 18/comments.json error Not Found. Did I write something wrong here? – bdj_ Nov 08 '14 at 11:09
  • 1
    @FakeRainBrigand - Post your comment as an answer so Akashbdj can accept. – Ashley Nov 08 '14 at 12:28
  • I think I found the problem in the 2nd question. Actually, I forgot to create the `destroy` action in my CommentsController. Secondly, I needed to add the `commentId` to my `this.props.url` so that it points to the right comment. But, I don't understand why is it trying to delete the article as well when I write `if @comment.destroy redirect_to article_path(@article)` ? – bdj_ Nov 08 '14 at 16:22
  • @Ash, it's just a typo, the question should be closed. – Brigand Nov 08 '14 at 17:00

1 Answers1

4

The function passed to map will not automatically share a this pointer with your react class.

To use this inside the anonymous function, call .bind(this) at the end of the function definition to yield a function with the expected this inside.

var commentNodes = this.props.comments.map(function (comment, index) {
    ...
});

Becomes:

var commentNodes = this.props.comments.map(function (comment, index) {
    ...
}.bind(this));
Catskul
  • 17,916
  • 15
  • 84
  • 113