3

I am new to react and Im trying to add li to ul dynamically using jquery. Inside my li I have a sapn with onclick method. When I click the span I want specific method to fire but I get - Uncaught ReferenceError: deleteMsg is not defined at HTMLSpanElement.onclick. I've searched for solution but nothing worked. I don't understand what is the problem...

This is my code:

    class CoachPage extends React.Component {

      constructor(props, context) {
        super(props, context);

        this.state={
          val: []
        }
      }

      handleSend(msg){

        this.state.val.push(msg);
        this.setState({val: []});
    }

    // get all data from db and put in the list
    componentWillMount(){
        fetch('http://localhost:3003/api/msgs/')
        .then(function(res) {
          return res.json();
          }).then(function(data){
            var msgs = [data];
             msgs[0].map(function(msg){
                console.log(msg.msgdata);

//Here i add the li's with a sapn and onclick method called "deleteMsg"
                $('#coach-panel-content').append( 
                  (`<li class=myli>${msg.msgdata}<span onclick=deleteMsg('${msg._id}')>X</span></li><hr>`));
             })
          })
        .catch(function(error) {
          console.log(error)
        }); 
    }

     deleteMsg(item){
        return fetch('http://localhost:3003/api/msgs/' + item, {
          method: 'delete'
        }).then(response =>
          response.json().then(json => {
            return json;
          })
        );

      }

      render() {
        return (
          <div className="container"  style={{color: '#FFF', textAlign: 'right'}}>
            <h1>Coach Page</h1>
            <AddMsg onSend={this.handleSend.bind(this)}  />
            <Panel header="עדכונים" bsStyle="info" style={{float: 'left', textAlign: 'right', width: '40em'}}>
              <ul id="coach-panel-content">


              </ul>
            </Panel>
          </div>
        );
      }
    }

    export default CoachPage;

UPDATE:

I made all the changes @sandor vasas said and I didn't noticed until now, but when I'm trying to add new msg i get this error: "Uncaught ReferenceError: val is not defined". I'm not sure I understand why is that happen.. this is my updated code:

class CoachPage extends React.Component {

  constructor(props, context) {
    super(props, context);

    this.state={
      val: []
    }
  }

  handleSend(msg){
    this.state.val.push(msg);
    this.setState({val});
}


// get all data from db and put in the list
componentDidMount(){
  fetch('http://localhost:3003/api/msgs/')
    .then( res => res.json() )
    .then( data => this.setState({ val: data }))
    .catch( console.error ); 
}

 deleteMsg(item){
    return fetch('http://localhost:3003/api/msgs/' + item, {
      method: 'DELETE'
    }).then(response =>
      response.json()
      .then(json => {
        return json;

      })
    );

  }

  render() {
    return (
      <div className="container"  style={{color: '#FFF', textAlign: 'right'}}>
        <h1>Coach Page</h1>
        <AddMsg onSend={this.handleSend.bind(this)}/>
        <Panel header="עדכונים" bsStyle="info" style={{float: 'left', textAlign: 'right', width: '40em'}}>
        <ul id="coach-panel-content">
        { 
          this.state.val.map( (msg, index) =>
            <li key={index} className='myli'>
              {msg.msgdata}
              <span onClick={() => this.deleteMsg(msg._id)}>X</span>
              <hr/>
            </li>
          )
        }
        </ul>
        </Panel>
      </div>
    );
  }
}

export default CoachPage;

2 Answers 2

2

Might I suggest avoiding jQuery for this use case?

React as a view library is suitable enough to handle the display of incoming data using something as simple as state change. Here is some pseudo code to get you started:

class CoachPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = { data: [] };
  }

  componentDidMount() {
    fetchYourData.then(data => {
      this.setState({ data: data });
    });
  }

  listItems() {
    return this.state.data.map(msg => {
      return (
        <li class="someClass">
          {msg.msgdata}
          <span onClick={() => (deleteMsg(msg._id)})>X</span>
          <hr />
        </li>
      );
    });
  }

  render() {
    return (
      // your other code
      <ul id="coach-panel-content">
        {this.state.data.length ? this.listItems() : null}
      </ul>
    );
  }
}

Upon success of your data fetch, we call setState - this will cause a re-render of your component with the new data triggering the injection of list items

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

Comments

0

You don't need jQuery to do this. In fact, you should use only the React state.

First, your

handleSend(msg){
    this.state.val.push(msg);
    this.setState({val: []});
}

should be

handleSend(msg){
    this.state.val.push(msg);
    this.setState({ val : this.state.val });
}

You were pushing an element to the array, but updating the state with an empty array, thereby erasing everything. Just call setState({ val: val }) or setState({ val }) (shorthand) to update the state with the same array reference and trigger re-rendering.

Assuming your API returns an array, you can just update the state with it directly, no need for jQuery or making another array of it.

componentWillMount(){
    fetch('http://localhost:3003/api/msgs/')
      .then( res => res.json() )
      .then( data => this.setState({ val: data }))
      .catch( console.error ); 
}

In render, you output the state's val array:

render() {
    return (
      <div className="container"  style={{color: '#FFF', textAlign: 'right'}}>
        <h1>Coach Page</h1>
        <AddMsg onSend={this.handleSend.bind(this)}  />
        <Panel header="עדכונים" bsStyle="info" style={{float: 'left', textAlign: 'right', width: '40em'}}>
          <ul id="coach-panel-content">
          { 
            this.state.val.map( msg =>
              <li class='myli'>
                {msg.msgdata}
                <span onClick={() => this.deleteMsg(msg._id)}>X</span>
              </li>
            )
          }
          </ul>
        </Panel>
      </div>
    );
  }

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.