Search code examples
javascriptjqueryhtmlcanvasjs

Create a canvasjs on submit on a dynamically generated element


NEW to javascript, jquery, and CanvasJS!

Here's my problem:

As you can notice, I'm going to submit a bunch of data with ajax. Since some don't exist, I'm gonna attach the event onsubmit, to make it works.

Now, my problem is the chart: I'm using CanvasJS to create my chart, and right before the code to make it happens, I created a div dynamically with the id chartContainer, and right after I will initiate the cart with the function CanvasJS.Chart().

The problem is that, if I create the div in the html file, the code will work, but if I will create the div in the script, the code will fail because:

CanvasJS Error: Chart Container with id "chartContainer" was not found.

How can I overcome the problem?

$(document).ready(function() {

  $(document).on('submit', 'form', function(event) {

    $.ajax({
      type: 'POST',
      url: $(this).attr("action"),
      data: $(this).serialize(),
      dataType: 'json',
      encode: true
    }).done(function(data) {

      var result = data.kg / Math.pow((data.centimeter / 100), 2);

      var result3 = result.toFixed(2);
      var result2 = '<div class="results">' + result.toFixed(2);
      result2 += '<div id="clickhere">back</div>';

      if (result > 25) {
        result2 += '<div>Your should loose at least the 5% of your weight</div>'
      } else if (result > 18.5) {
        result2 += '<div>Your weight is ideal</div>'
      } else {
        result2 += '<div>You\'re underweight, you should take integrate your diet with different food and eat more often</div>'
      }

      result2 += '<div id="chartContainer"></div>'

      var gauge = {
        title: {
          text: "BMI"
        },
        data: {
          y: result3
        },
        maximum: 30
      };

      var chart = new CanvasJS.Chart("chartContainer");
      createGauge(chart);

      function createGauge(chart) {
        gauge.unoccupied = {
          y: gauge.maximum - gauge.data.y,
          color: "#e3e3e3",
          toolTipContent: null,
          highlightEnabled: false,
          click: function() {
            gauge.unoccupied.exploded = true;
          }
        }
        gauge.data.click = function() {
          gauge.data.exploded = true;
        };
        if (!gauge.data.color)
          gauge.data.color = "#6b58f2";
        gauge.valueText = {
          text: gauge.data.y.toString(),
          verticalAlign: "center"
        };

        var data = {
          type: "doughnut",
          dataPoints: [{
              y: gauge.maximum,
              color: "transparent",
              toolTipContent: null
            },
            gauge.data,
            gauge.unoccupied
          ],
        };

        if (!chart.options.data)
          chart.options.data = [];
        chart.options.data.push(data);

        if (gauge.title) {
          chart.options.title = gauge.title;
        }

        if (!chart.options.subtitles)
          chart.options.subtitles = [];
        chart.options.subtitles.push(gauge.valueText);

        chart.render();
      }

      result2 += '</div>';

      var clickhere = $('#clickhere');
      var form = $('form');
      $('form').replaceWith(result2);
      $(document).on("click", "#clickhere", function() {
        $('.results').remove();
      });
    });

    event.preventDefault();
  });

});
<form action="/send.php" id="formid" method="post">
  <div class="row">
    <div class="col-md-4">
      <div class="row">
        <h3 class="col-md-9">Height</h3>
        <p class="switch col-md-3">cm</p>
      </div>

      <div class="antbits-bmi-form_section_layer antbits-bmi-metric">
        <div>
          <label for="antbits-bmi-cm" class="antbits-bmi-form_section_label">Centimetres</label>
          <input class="form-control" id="antbits-bmi-cm" aria-describedby="antbits-bmi-form_height-error" alt="height, centimeters" inputmode="numeric" type="text" step="0.1" min="0" maxlength="5" name="centimeter" placeholder="cm" required="">
        </div>
      </div>
    </div>
    <div class="col-md-4">
      <div class="row">
        <h3 class="col-md-9">Weight</h3>
        <p class="col-md-3 switch">st, lb</p>
      </div>
      <div class="antbits-bmi-form_section_layer antbits-bmi-imperial">
        <div>
          <label for="antbits-bmi-kg" class="antbits-bmi-form_section_label">Kg</label>
          <input class="form-control" id="antbits-bmi-kg" placeholder="Kg" alt="kg" type="text" inputmode="numeric" min="0" maxlength="2" name="kg" required="">
        </div>

      </div>
    </div>
    <div class="col-md-4">
      <h3>Age</h3>
      <div class="antbits-bmi-form_section_inner">
        <div>
          <label for="antbits-bmi-age" class="antbits-bmi-form_section_label antbits-accessible_hidden">Age in years</label>
          <select class="form-control" id="age" name="age" required=""></select>
        </div>
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-md-4">
      <h3>Sex<small>?</small></h3>
      <div class="info hide">
        <h3>Sex<small>?</small></h3>
        <p>For children, BMI centile is gender specific. For both children and adults, we give more personalised information based on whether you are male or female.</p>
      </div>
      <div class="radio-click row height">
        <div class="radio-inline col-md-6 checked" id="male">
          <input type="radio" name="optradio" value="male">Male
        </div>
        <div class="radio-inline col-md-6" id="female">
          <input type="radio" name="optradio" value="female">Female
        </div>
      </div>
    </div>
    <div class="col-md-4">
      <h3>Ethnic Group (optional)<small>?</small></h3>
      <div class="info hide">
        <h3>Ethnic</h3>
        <p>Black, Asian and other minority ethnic groups with a BMI of 23 or more have a higher risk of getting type 2 diabetes and other long term illnesses.</p>
      </div>
      <select class="form-control" id="antbits-bmi-ethnicity" alt="Ethnic group" name="ethnic" required="">
        <option disabled selected value class="antbits-bmi-form_option">Not stated</option>
        <option value="2" class="antbits-bmi-form_option">White</option>
        <option value="3" class="antbits-bmi-form_option">Black Caribbean</option>
        <option value="4" class="antbits-bmi-form_option">Black African</option>
        <option value="5" class="antbits-bmi-form_option">Indian</option>
        <option value="6" class="antbits-bmi-form_option">Pakistani</option>
        <option value="7" class="antbits-bmi-form_option">Bangladeshi</option>
        <option value="8" class="antbits-bmi-form_option">Chinese</option>
        <option value="9" class="antbits-bmi-form_option">Middle Eastern</option>
        <option value="10" class="antbits-bmi-form_option">Mixed</option>
        <option value="11" class="antbits-bmi-form_option">Other</option>
      </select>
    </div>
  </div>
  <div class="row">
    <div class="col-md-12">
      <h3>Activity Level</h3>
      <p>So we can personalize your results</p>
      <div class="slidercontainer">
        <input type="range" min="0" max="150" value="75" class="slider" id="myRange" name="range">
        <div class="row center height activity">
          <div class="col-md-4">
            <p>Inactive</p>
          </div>
          <div class="col-md-4">
            <p>Moderate Active</p>
          </div>
          <div class="col-md-4">
            <p>Active</p>
          </div>
        </div>
        <div class="row center height">
          <div class="col-md-4">
            <p>Less than 30 minutes a week</p>
          </div>
          <div class="col-md-4">
            <p>Between 30 and 60 minutes a week</p>
          </div>
          <div class="col-md-4">
            <p>Between 60 and 150 minutes a week</p>
          </div>
        </div>
        <p>Value: <span id="demo"></span></p>
      </div>
    </div>

  </div>
  <!-- <div id="chartContainer"></div> -->
  <div class="center">
    <input type="submit" value="Calculate">
  </div>
</form>

Solution

  • Append the div to the document before calling the chart.

    You need to move

    result2 += '</div>';
    var clickhere = $('#clickhere');
    var form = $('form');
    $('form').replaceWith(result2);
    

    to right before

    var chart = new CanvasJS.Chart("chartContainer");
    createGauge(chart);
    

    You can even more the function outside as well. It is not needed inside the document.ready

    And this

    $(document).on("click", "#clickhere", function() {
      $('.results').remove();
    });
    

    does not belong in the .done either

    Here is a better version

    function createGauge(chart) {
      gauge.unoccupied = {
        y: gauge.maximum - gauge.data.y,
        color: "#e3e3e3",
        toolTipContent: null,
        highlightEnabled: false,
        click: function() {
          gauge.unoccupied.exploded = true;
        }
      }
      gauge.data.click = function() {
        gauge.data.exploded = true;
      };
      if (!gauge.data.color)
        gauge.data.color = "#6b58f2";
      gauge.valueText = {
        text: gauge.data.y.toString(),
        verticalAlign: "center"
      };
    
      var data = {
        type: "doughnut",
        dataPoints: [{
            y: gauge.maximum,
            color: "transparent",
            toolTipContent: null
          },
          gauge.data,
          gauge.unoccupied
        ],
      };
    
      if (!chart.options.data)
        chart.options.data = [];
      chart.options.data.push(data);
    
      if (gauge.title) {
        chart.options.title = gauge.title;
      }
    
      if (!chart.options.subtitles)
        chart.options.subtitles = [];
      chart.options.subtitles.push(gauge.valueText);
    
      chart.render();
    }
    
    
    $(function() {
    
      $(document).on("click", "#clickhere", function() {
        $('.results').remove();
      });
    
    
      $(document).on('submit', 'form', function(event) {
        event.preventDefault();
    
        $.ajax({
          type: 'POST',
          url: $(this).attr("action"),
          data: $(this).serialize(),
          dataType: 'json',
          encode: true
        }).done(function(data) {
    
          var result = data.kg / Math.pow((data.centimeter / 100), 2);
    
          var result3 = result.toFixed(2);
          var result2 = '<div class="results">' + result.toFixed(2);
          result2 += '<div id="clickhere">back</div>';
    
          if (result > 25) {
            result2 += '<div>Your should loose at least the 5% of your weight</div>'
          } else if (result > 18.5) {
            result2 += '<div>Your weight is ideal</div>'
          } else {
            result2 += '<div>You\'re underweight, you should take integrate your diet with different food and eat more often</div>'
          }
    
          result2 += '<div id="chartContainer"></div>'
          result2 += '</div>';
          var form = $('form');
          $('form').replaceWith(result2);
    
    
          var gauge = {
            title: {
              text: "BMI"
            },
            data: {
              y: result3
            },
            maximum: 30
          };
    
          var chart = new CanvasJS.Chart("chartContainer");
          createGauge(chart);
        });
      });
    });
    <form action="/send.php" id="formid" method="post">
      <div class="row">
        <div class="col-md-4">
          <div class="row">
            <h3 class="col-md-9">Height</h3>
            <p class="switch col-md-3">cm</p>
          </div>
    
          <div class="antbits-bmi-form_section_layer antbits-bmi-metric">
            <div>
              <label for="antbits-bmi-cm" class="antbits-bmi-form_section_label">Centimetres</label>
              <input class="form-control" id="antbits-bmi-cm" aria-describedby="antbits-bmi-form_height-error" alt="height, centimeters" inputmode="numeric" type="text" step="0.1" min="0" maxlength="5" name="centimeter" placeholder="cm" required="">
            </div>
          </div>
        </div>
        <div class="col-md-4">
          <div class="row">
            <h3 class="col-md-9">Weight</h3>
            <p class="col-md-3 switch">st, lb</p>
          </div>
          <div class="antbits-bmi-form_section_layer antbits-bmi-imperial">
            <div>
              <label for="antbits-bmi-kg" class="antbits-bmi-form_section_label">Kg</label>
              <input class="form-control" id="antbits-bmi-kg" placeholder="Kg" alt="kg" type="text" inputmode="numeric" min="0" maxlength="2" name="kg" required="">
            </div>
    
          </div>
        </div>
        <div class="col-md-4">
          <h3>Age</h3>
          <div class="antbits-bmi-form_section_inner">
            <div>
              <label for="antbits-bmi-age" class="antbits-bmi-form_section_label antbits-accessible_hidden">Age in years</label>
              <select class="form-control" id="age" name="age" required=""></select>
            </div>
          </div>
        </div>
      </div>
      <div class="row">
        <div class="col-md-4">
          <h3>Sex<small>?</small></h3>
          <div class="info hide">
            <h3>Sex<small>?</small></h3>
            <p>For children, BMI centile is gender specific. For both children and adults, we give more personalised information based on whether you are male or female.</p>
          </div>
          <div class="radio-click row height">
            <div class="radio-inline col-md-6 checked" id="male">
              <input type="radio" name="optradio" value="male">Male
            </div>
            <div class="radio-inline col-md-6" id="female">
              <input type="radio" name="optradio" value="female">Female
            </div>
          </div>
        </div>
        <div class="col-md-4">
          <h3>Ethnic Group (optional)<small>?</small></h3>
          <div class="info hide">
            <h3>Ethnic</h3>
            <p>Black, Asian and other minority ethnic groups with a BMI of 23 or more have a higher risk of getting type 2 diabetes and other long term illnesses.</p>
          </div>
          <select class="form-control" id="antbits-bmi-ethnicity" alt="Ethnic group" name="ethnic" required="">
            <option disabled selected value class="antbits-bmi-form_option">Not stated</option>
            <option value="2" class="antbits-bmi-form_option">White</option>
            <option value="3" class="antbits-bmi-form_option">Black Caribbean</option>
            <option value="4" class="antbits-bmi-form_option">Black African</option>
            <option value="5" class="antbits-bmi-form_option">Indian</option>
            <option value="6" class="antbits-bmi-form_option">Pakistani</option>
            <option value="7" class="antbits-bmi-form_option">Bangladeshi</option>
            <option value="8" class="antbits-bmi-form_option">Chinese</option>
            <option value="9" class="antbits-bmi-form_option">Middle Eastern</option>
            <option value="10" class="antbits-bmi-form_option">Mixed</option>
            <option value="11" class="antbits-bmi-form_option">Other</option>
          </select>
        </div>
      </div>
      <div class="row">
        <div class="col-md-12">
          <h3>Activity Level</h3>
          <p>So we can personalize your results</p>
          <div class="slidercontainer">
            <input type="range" min="0" max="150" value="75" class="slider" id="myRange" name="range">
            <div class="row center height activity">
              <div class="col-md-4">
                <p>Inactive</p>
              </div>
              <div class="col-md-4">
                <p>Moderate Active</p>
              </div>
              <div class="col-md-4">
                <p>Active</p>
              </div>
            </div>
            <div class="row center height">
              <div class="col-md-4">
                <p>Less than 30 minutes a week</p>
              </div>
              <div class="col-md-4">
                <p>Between 30 and 60 minutes a week</p>
              </div>
              <div class="col-md-4">
                <p>Between 60 and 150 minutes a week</p>
              </div>
            </div>
            <p>Value: <span id="demo"></span></p>
          </div>
        </div>
    
      </div>
      <!-- <div id="chartContainer"></div> -->
      <div class="center">
        <input type="submit" value="Calculate">
      </div>
    </form>