dorkycam
dorkycam

Reputation: 529

Calling a function inside render function - ReactJS?

Ok so I am making a "buzzfeed" quiz generator and I am having an issue with a piece of my form. So for each question made there are two different parts, a "Question" and the "Answers". There will always be 4 answers but I want to keep track of which Answers are checked later so I would like to give each answer a unique id "question" + questionNum + "Answer" + answerNum or "question" + questionNum + "Answer" + i So I made this answersGenerator function that is supposed to give me 4 unique answer choice fill ins for the user to input answers for that specific questions (right now it says something about terms and conditions - ignore that I ad just left it like that for now because I was following a tutorial). Here is all my code:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import logo from './logo.svg';
import './App.css';

var questionNum = 1;
var answerNum = 1;

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      quizTitle: "",
      author: "",
      question: "",
      terms: false,
      test: "",
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  handleSubmit(event) {
    event.preventDefault();
    console.log(this.state);
  }

  render() {
    return (
      <div className="App">
        <div>
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <h1 className="App-title">Welcome to React</h1>
          </header>
          <p className="App-intro">
            To get started, edit <code>src/App.js</code> and save to reload.
          </p>
        </div>

        <div className="container">
          <div className="columns">
            <div className="formDiv">
              <form className="form" onSubmit={this.handleSubmit}>
                <div className="field">
                  <label className="label">Give your quiz a title.</label>
                  <div className="control">
                    <input
                      className="input"
                      type="text"
                      name="quizTitle"
                      value={this.state.quizTitle}
                      onChange={this.handleChange}
                    />
                  </div>
                </div>

                <div className="field">
                  <label className="label">Who's the Author?</label>
                  <div className="control">
                    <input
                      className="input"
                      type="text"
                      name="author"
                      value={this.state.author}
                      onChange={this.handleChange}
                    />
                  </div>
                </div>

                <div className="questions" id="questions">
                  <div className="question" id={'questionGroup' + questionNum}>
                    <div className="field">
                      <label className="label" id={'question' + questionNum}>Question {questionNum}</label>
                      <div className="control">
                        <input
                          className="input"
                          type="text"
                          name='question'
                          value={this.state.question}
                          onChange={this.handleChange}
                        />
                      </div>
                    </div>

                    <div className="answersDiv">
                    <label className="label">Answers</label>
                      <div className="field">
                        <div className="control">
                          <label className="checkbox">
                              {this.answersGenerator()}
                          </label>
                        </div>
                      </div>
                    </div>

                </div>
              </div>
              <div className="field">
                  <div className="endButtons">
                    <button id="addQuestionButton"
                      onClick={addQuestion}>Add Question</button>
                    <input
                      type="submit"
                      value="Submit"
                      id="submitButton"
                      className="button is-primary"
                    />
                  </div>
              </div>
              </form>
          </div>

            <div className="column is-3">
              <pre>
                <code>
                  <p>Quiz Title: {this.state.quizTitle}</p>
                  <p>Author: {this.state.author}</p>
                  <p>Question: {this.state.question}</p>
                  <p>Terms and Condition: {this.state.terms}</p>
                  <p>Do you test?: {this.state.test}</p>
                </code>
              </pre>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

function answersGenerator () {

  console.log("hello this is answer generator");
  var div = document.createElement('div');
  div.className = 'answers' + {questionNum};

  for (var i = 1; i < 5; i++){

    div.innerHTML = 
      '<div className="field">\
      <div className="control">\
        <label className="checkbox">\
        <label className="label">Answers</label>\
            <input\
              name="terms"\
              type="checkbox"\
              id="question'+{questionNum}+'Answer'+{i}+'"\
              checked={this.state.terms}\
              onChange={this.handleChange}\
            />\
            I agree to the{" "}\
            <a href="https://google.com">terms and conditions</a>\
        </label>\
      </div>';
    document.getElementsByClassName('answersDiv')[0].appendChild(div)
  }
}


function addQuestion () {
  questionNum++;
  console.log(questionNum + "that is the question number");

  var div = document.createElement('div');

    div.className = "questions" + questionNum;

    div.innerHTML =
        '<div id="questionGroup'+{questionNum}+'">\
        Question '+{questionNum}+'<br />\
        <input type="text" name="question'+{questionNum}+'"/><br />\
        Answers<br />\
        Check the box(es) for the correct answer(s).<br />\
        <input type="checkbox" name="question'+{questionNum}+'Answer1Box" />\
        <label for="question'+{questionNum}+'Answer1"><input type="text" name="question'+{questionNum}+'Answer1"/></label><br />\
        <input type="checkbox" name="question'+{questionNum}+'Answer2Box" id= />\
        <label for="question'+{questionNum}+'Answer2"><input type="text" name="question'+{questionNum}+'Answer2"/></label><br />\
        <input type="checkbox" name="question'+{questionNum}+'Answer3Box"  />\
        <label for="question'+{questionNum}+'Answer3"><input type="text" name="question'+{questionNum}+'Answer3"/></label><br />\
        <input type="checkbox" name="question'+{questionNum}+'Answer4Box"  />\
        <label for="question'+{questionNum}+'Answer4"><input type="text" name="question'+{questionNum}+'Answer4"/></label><br />\
        </div>';

      document.getElementsByClassName('questions')[0].appendChild(div)


}


export default App;

There's a few things to just ignore in here, i just wasn't sure how much info you needed. So the issue is that I get an error when I call my answersGenerator function in my render function. Here's the error Uncaught TypeError: this.answersGenerator is not a function Here's the small piece where that is

            <div className="answersDiv">
            <label className="label">Answers</label>
              <div className="field">
                <div className="control">
                  <label className="checkbox">
                      {this.answersGenerator()}
                  </label>
                </div>
              </div>
            </div>

I appreciate the help, if you have any other tips for me other than this issue I am having I am all ears. I am very new at this, being js and React.

UPDATE: I have edited the answersDiv to be just this (I relized it was being called inside a checkbox)

        <div className="answersDiv">
        <label className="label">Answers</label>

                  {answersGenerator()}

        </div>

I am still getting the same errors though.

Upvotes: 1

Views: 8394

Answers (2)

reisdev
reisdev

Reputation: 3403

You're receiving the error because the answersGenerator() isn't a method of your class App, so, you can't refer to it using this. If you want to do on that way, move you function to inside the component, like this:

class App extends Component {
    // your component definition etc..
    answersGenerator = () => {
        // your function implementation
    }
    // the rest of your component
}

TIP:

If you dont want to have to always bind the function, like:

this.handleChange = this.handleChange.bind(this);

Declare your method like:

handleChange = (event) => { // the implementation }

Instead of

handleChange(event) { // the implementation }

The () => {}, known as arrow function, does the bind for your.

EDIT

You're developing with React, that supports creating HTML inside your code. So, you can create an array of answers, then, return a div with the answers mapped inside. The map will take each answer and render inside the div. Try to define your method as below:

answersGenerator => () {
    console.log("hello this is answer generator");
    var answers = []
    for (var i = 1; i < 5; i++){
      answers.push(
        <div className="field">
          <div className="control">
            <label className="checkbox">
               <label className="label">Answers</label>
               <input
                 name="terms"
                 type="checkbox"
                 id=`question${questionNum}Answer${i}`
                 checked={this.state.terms} 
                 onChange={this.handleChange}
               />
               I agree to the{" "}
               <a href="https://google.com">terms and conditions</a>
           </label>
         </div>
       );
    } 
    return <div className=`answer${questionNum}`> {answers.map(answer => answer)} </div>
}

Upvotes: 1

Colin Ricardo
Colin Ricardo

Reputation: 17269

At first glance it looks like you haven't defined your answersGenerator() function within your App class.

Thus, this.answersGenerator() doesn't exist.

Try just using answersGenerator() without the this.

Upvotes: 0

Related Questions