Home > Software design >  AppsScript -> WebApp -> Event listeners don't work if element added after DOMContentLoade
AppsScript -> WebApp -> Event listeners don't work if element added after DOMContentLoade

Time:02-05

I have a webapp that retrieves from a Google sheet an array of values to dynamically create a table so if the array retrieved has four items, then the table has four rows, and so on.Each row has as first column item a toggle to disables the other columns' input fields for that row.

It looks like this:

I initially created everything statically, just to get it working first, with five sample rows, and got every thing working, the toggle worked and disabled and cleared content, etc. However, as I wrote in the part to dynamically create the table rows and the event listeners for each toggle, the toggle stopped responding, even though the function for each is named correctly according to the dynamically created event listeners.

These rows are done in the javascript for the page, using this statement:

document.addEventListener('DOMContentLoaded', setup_ui);

After creating the table rows and before the end of the setup_ui function, I create the event listeners for each toggle.

// Next we need to create event listeners to make the toggles usables
for(var i = 0; i < domains_count; i  ){
  let number = i 1;
  let domain_toggle = `domain${number}`;
  let function_name = `switch_for_dom${number}`;
  document.getElementById(domain_toggle).addEventListener("click",function_name);
}

You see, at this point, I do have the rows created, they show up, all appears well. And yet, if I do

alert(document.getElementById("domain1"))

It doesn't find it... even though its in front of me and I can right click on the page, go into dev tools and see it there.

The code for the function handling the toggle is there below in the file, here's the first function for the first toggle.

function switch_for_dom1(){

let check = document.getElementById("domain1");

if(check.checked == true){

document.getElementById("first_name_domain1").disabled = false;
document.getElementById("last_name_domain1").disabled = false;
document.getElementById("email_domain1").disabled = false;
document.getElementById("phone_domain1").disabled = false;
document.getElementById("position_domain1").disabled = false;
document.getElementById("role_domain1").disabled = false;


}else{

document.getElementById("first_name_domain1").disabled = true;
document.getElementById("last_name_domain1").disabled = true;
document.getElementById("email_domain1").disabled = true;
document.getElementById("phone_domain1").disabled = true;
document.getElementById("position_domain1").disabled = true;
document.getElementById("role_domain1").disabled = true;
document.getElementById("first_name_domain1").value = "";
document.getElementById("last_name_domain1").value = "";
document.getElementById("email_domain1").value = "";
document.getElementById("phone_domain1").value = "";
document.getElementById("position_domain1").value = "";
document.getElementById("role_domain1").value = "Role";
}
}

How can I not only create those table rows dynamically, as I have done here, but also have the event listeners I create dynamically actually work with the functions that are later down in that js file?

I will have to eventually have the functions to handle the toggles created dynamically as well and I have no clue at this point.

To replicate this you'd need yourself a new AppScript project webapp. Here's the code for my html and js.

HTML:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">

        <?!= include('menu-css'); ?>
        <?!= include('users-css'); ?>
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
  </head>
  <body >
    
    <?!= include('menu'); ?>

    <div >
      <h5 id="title"> Create User</h5> </br>
      <div >
        <div >
          <input type="text"  placeholder="first name" aria-label="first name" id="first_name">
        </div>
        <div >
          <input type="text"  placeholder="last name" aria-label="last name" id="last_name">
        </div>
        <div >
          <input type="text"  placeholder="email" aria-label="email" id="email">
        </div>
      </div>
      </br>
      <div >
        <div >
          <input type="text"  placeholder="Phone number" aria-label="Phone number" id="phone">
        </div>
        <div >
          <input type="text"  placeholder="Company Position" aria-label="Company Position" id="position">
        </div>
        <div >
          <select  aria-label="Default select example" id="role">
            <option selected>Role</option>
            <option value="1">Superuser</option>
            <option value="2">Requester</option>
            <option value="3">Reporter</option>
            <option value="4">Receiver</option>
            <option value="5">Purchaser</option>
            <option value="6">Finance</option>
            <option value="7">Approver</option>
            <option value="8">Peasant</option>
          </select>       
        </div>
      </div>    
      </br>
      <div >
      <div >
        <input  type="checkbox" id="alldomains">
        <label  for="flexSwitchCheckDefault">All Domains</label>
      </div>


    
      <table >
        <thead>
          <tr>
            <th scope="col" >
              Domains
            </th>
            <th scope="col">
              First name
            </th>
            <th scope="col">
              Last name
            </th>
            <th scope="col">
              Email
            </th>
            <th scope="col">
              Phone number
            </th>
            <th scope="col">
              company position
            </th>
            <th scope="col">
              Role
            </th>
          </tr>
        </thead>
        <tbody id="tbody">
        </tbody>

      </table>
      
    </div>
    <?!= include('menu-js'); ?>
    <?!= include('users-js'); ?>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC nuZB EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
  </body>


</html>

And now the Javascript:

    <script>

document.addEventListener('DOMContentLoaded', setup_ui);

function setup_ui(){

  var count = 4;
  document.getElementById("title").innerHTML = `Create a User across any number of your ${count} domains`;

  create_table();

  document.getElementById("alldomains").click();
  document.getElementById("alldomains").click();
}


google.script.run.withSuccessHandler(create_table).get_domains_names();


function create_table(domains_names){
  var domains_count = domains_names.length;
  var row_html;

  if(domains_count > 0){

    var table = document.getElementById("tbody");
    var table_body = table.innerHTML;

    for(var i = 0; i < domains_count; i  ){
      
      let domain = domains_names[i];
      let number = i 1;
      
      row_html = `
        <tr>
          <td>
            <div >
              <input  type="checkbox" id="domain${number}">
              <label  for="flexSwitchCheckDefault">${domain}</label>
            </div>              
          <td>
            <input type="text"  placeholder="first name" aria-label="first name" id="first_name_domain${number}">
          </td>
          <td>                
            <input type="text"  placeholder="last name" aria-label="last name" id="last_name_domain${number}">
          </td>
          <td>
            <input type="text"  placeholder="email" aria-label="email" id="email_domain${number}">
          </td>
          <td>
            <input type="text"  placeholder="Phone number" aria-label="Phone number" id="phone_domain${number}">
          </td>
          <td>
            <input type="text"  placeholder="Company Position" aria-label="Company Position" id="position_domain${number}">
          </td>
          <td>
            <select  aria-label="Default select example" id="role_domain${number}">
              <option selected>Role</option>
              <option value="1">Superuser</option>
              <option value="2">Requester</option>
              <option value="3">Reporter</option>
              <option value="4">Receiver</option>
              <option value="5">Purchaser</option>
              <option value="6">Finance</option>
              <option value="7">Approver</option>
              <option value="8">Peasant</option>
            </select>
          </td>
        </tr>        
      `;

            let row = document.createElement("tr");
            row.innerHTML = row_html;
            tbody.appendChild(row);        
    }


    // Next we need to create event listeners to make the toggles usables
    for(var i = 0; i < domains_count; i  ){
      let number = i 1;
      let domain_toggle = `domain${number}`;
      let function_name = `switch_for_dom${number}`;
      document.getElementById(domain_toggle).addEventListener("click",function_name);
    }

    // Next we need to create the functions to provide the functionality for each toggles

    
  }else{ // no domains (they need to add the domains)

  }
}


document.getElementById("alldomains").addEventListener("click",applyAllDomains);

function applyAllDomains(){

  document.getElementById("domain1").click();
  document.getElementById("domain2").click();
  document.getElementById("domain3").click();
  document.getElementById("domain4").click();
  document.getElementById("domain5").click();

  switch_for_dom1();
  switch_for_dom2();
  switch_for_dom3();
  switch_for_dom4();
  switch_for_dom5();
  
}

document.getElementById("first_name").addEventListener("input",map_first_name);
document.getElementById("last_name").addEventListener("input",map_last_name);
document.getElementById("email").addEventListener("input",map_email);
document.getElementById("phone").addEventListener("input",map_phone);
document.getElementById("position").addEventListener("input",map_position);
document.getElementById("role").addEventListener("input",map_role);


function map_first_name(){

  alert("here");
  var fn = document.getElementById("first_name").value;

  if(document.getElementById("first_name_domain1").disabled == false){
    document.getElementById("first_name_domain1").value = fn;
  }  
  if(document.getElementById("first_name_domain2").disabled == false){
    document.getElementById("first_name_domain2").value = fn;
  }  
  if(document.getElementById("first_name_domain3").disabled == false){
    document.getElementById("first_name_domain3").value = fn;
  }  
  if(document.getElementById("first_name_domain4").disabled == false){
    document.getElementById("first_name_domain4").value = fn;
  }  
  if(document.getElementById("first_name_domain5").disabled == false){
    document.getElementById("first_name_domain5").value = fn;
  }
    
}

function map_last_name(){

  var fn = document.getElementById("last_name").value;

  if(document.getElementById("last_name_domain1").disabled == false){
    document.getElementById("last_name_domain1").value = fn;
  }  
  if(document.getElementById("last_name_domain2").disabled == false){
    document.getElementById("last_name_domain2").value = fn;
  }  
  if(document.getElementById("last_name_domain3").disabled == false){
    document.getElementById("last_name_domain3").value = fn;
  }  
  if(document.getElementById("last_name_domain4").disabled == false){
    document.getElementById("last_name_domain4").value = fn;
  }  
  if(document.getElementById("last_name_domain5").disabled == false){
    document.getElementById("last_name_domain5").value = fn;
  }
     
}

function map_email(){

  var fn = document.getElementById("email").value;

  if(document.getElementById("email_domain1").disabled == false){
    document.getElementById("email_domain1").value = fn;
  }  
  if(document.getElementById("email_domain2").disabled == false){
    document.getElementById("email_domain2").value = fn;
  }  
  if(document.getElementById("email_domain3").disabled == false){
    document.getElementById("email_domain3").value = fn;
  }  
  if(document.getElementById("email_domain4").disabled == false){
    document.getElementById("email_domain4").value = fn;
  }  
  if(document.getElementById("email_domain5").disabled == false){
    document.getElementById("email_domain5").value = fn;
  }
     
}


function map_phone(){

  var fn = document.getElementById("phone").value;

  if(document.getElementById("phone_domain1").disabled == false){
    document.getElementById("phone_domain1").value = fn;
  }  
  if(document.getElementById("phone_domain2").disabled == false){
    document.getElementById("phone_domain2").value = fn;
  }  
  if(document.getElementById("phone_domain3").disabled == false){
    document.getElementById("phone_domain3").value = fn;
  }  
  if(document.getElementById("phone_domain4").disabled == false){
    document.getElementById("phone_domain4").value = fn;
  }  
  if(document.getElementById("phone_domain5").disabled == false){
    document.getElementById("phone_domain5").value = fn;
  }
     
}



function map_position(){

  var fn = document.getElementById("position").value;

  if(document.getElementById("position_domain1").disabled == false){
    document.getElementById("position_domain1").value = fn;
  }  
  if(document.getElementById("position_domain2").disabled == false){
    document.getElementById("position_domain2").value = fn;
  }  
  if(document.getElementById("position_domain3").disabled == false){
    document.getElementById("position_domain3").value = fn;
  }  
  if(document.getElementById("position_domain4").disabled == false){
    document.getElementById("position_domain4").value = fn;
  }  
  if(document.getElementById("position_domain5").disabled == false){
    document.getElementById("position_domain5").value = fn;
  }
     
}



function map_role(){

  var fn = document.getElementById("role").value;

  if(document.getElementById("role_domain1").disabled == false){
    document.getElementById("role_domain1").value = fn;
  }  
  if(document.getElementById("role_domain2").disabled == false){
    document.getElementById("role_domain2").value = fn;
  }  
  if(document.getElementById("role_domain3").disabled == false){
    document.getElementById("role_domain3").value = fn;
  }  
  if(document.getElementById("role_domain4").disabled == false){
    document.getElementById("role_domain4").value = fn;
  }  
  if(document.getElementById("role_domain5").disabled == false){
    document.getElementById("role_domain5").value = fn;
  }
     
}




function switch_for_dom1(){

  let check = document.getElementById("domain1");

  if(check.checked == true){

    document.getElementById("first_name_domain1").disabled = false;
    document.getElementById("last_name_domain1").disabled = false;
    document.getElementById("email_domain1").disabled = false;
    document.getElementById("phone_domain1").disabled = false;
    document.getElementById("position_domain1").disabled = false;
    document.getElementById("role_domain1").disabled = false;

    
  }else{

    document.getElementById("first_name_domain1").disabled = true;
    document.getElementById("last_name_domain1").disabled = true;
    document.getElementById("email_domain1").disabled = true;
    document.getElementById("phone_domain1").disabled = true;
    document.getElementById("position_domain1").disabled = true;
    document.getElementById("role_domain1").disabled = true;
    document.getElementById("first_name_domain1").value = "";
    document.getElementById("last_name_domain1").value = "";
    document.getElementById("email_domain1").value = "";
    document.getElementById("phone_domain1").value = "";
    document.getElementById("position_domain1").value = "";
    document.getElementById("role_domain1").value = "Role";
  }
}



function switch_for_dom2(){

  let check = document.getElementById("domain2");

  if(check.checked == true){

    document.getElementById("first_name_domain2").disabled = false;
    document.getElementById("last_name_domain2").disabled = false;
    document.getElementById("email_domain2").disabled = false;
    document.getElementById("phone_domain2").disabled = false;
    document.getElementById("position_domain2").disabled = false;
    document.getElementById("role_domain2").disabled = false;

  }else{

    document.getElementById("first_name_domain2").disabled = true;
    document.getElementById("last_name_domain2").disabled = true;
    document.getElementById("email_domain2").disabled = true;
    document.getElementById("phone_domain2").disabled = true;
    document.getElementById("position_domain2").disabled = true;
    document.getElementById("role_domain2").disabled = true;
    document.getElementById("first_name_domain2").value = "";
    document.getElementById("last_name_domain2").value = "";
    document.getElementById("email_domain2").value = "";
    document.getElementById("phone_domain2").value = "";
    document.getElementById("position_domain2").value = "";
    document.getElementById("role_domain2").value = "Role";
  }
}



function switch_for_dom3(){

  let check = document.getElementById("domain3");
  if(check.checked == true){

    document.getElementById("first_name_domain3").disabled = false;
    document.getElementById("last_name_domain3").disabled = false;
    document.getElementById("email_domain3").disabled = false;
    document.getElementById("phone_domain3").disabled = false;
    document.getElementById("position_domain3").disabled = false;
    document.getElementById("role_domain3").disabled = false;

  }else{

    document.getElementById("first_name_domain3").disabled = true;
    document.getElementById("last_name_domain3").disabled = true;
    document.getElementById("email_domain3").disabled = true;
    document.getElementById("phone_domain3").disabled = true;
    document.getElementById("position_domain3").disabled = true;
    document.getElementById("role_domain3").disabled = true;
    document.getElementById("first_name_domain3").value = "";
    document.getElementById("last_name_domain3").value = "";
    document.getElementById("email_domain3").value = "";
    document.getElementById("phone_domain3").value = "";
    document.getElementById("position_domain3").value = "";
    document.getElementById("role_domain3").value = "Role";
  }
}



function switch_for_dom4(){

  let check = document.getElementById("domain4");

  if(check.checked == true){

    document.getElementById("first_name_domain4").disabled = false;
    document.getElementById("last_name_domain4").disabled = false;
    document.getElementById("email_domain4").disabled = false;
    document.getElementById("phone_domain4").disabled = false;
    document.getElementById("position_domain4").disabled = false;
    document.getElementById("role_domain4").disabled = false;

  }else{

    document.getElementById("first_name_domain4").disabled = true;
    document.getElementById("last_name_domain4").disabled = true;
    document.getElementById("email_domain4").disabled = true;
    document.getElementById("phone_domain4").disabled = true;
    document.getElementById("position_domain4").disabled = true;
    document.getElementById("role_domain4").disabled = true;
    document.getElementById("first_name_domain4").value = "";
    document.getElementById("last_name_domain4").value = "";
    document.getElementById("email_domain4").value = "";
    document.getElementById("phone_domain4").value = "";
    document.getElementById("position_domain4").value = "";
    document.getElementById("role_domain4").value = "Role";
  }
}



function switch_for_dom5(){

  let check = document.getElementById("domain5");

  if(check.checked == true){

    document.getElementById("first_name_domain5").disabled = false;
    document.getElementById("last_name_domain5").disabled = false;
    document.getElementById("email_domain5").disabled = false;
    document.getElementById("phone_domain5").disabled = false;
    document.getElementById("position_domain5").disabled = false;
    document.getElementById("role_domain5").disabled = false;

  }else{
    document.getElementById("first_name_domain5").disabled = true;
    document.getElementById("last_name_domain5").disabled = true;
    document.getElementById("email_domain5").disabled = true;
    document.getElementById("phone_domain5").disabled = true;
    document.getElementById("position_domain5").disabled = true;
    document.getElementById("role_domain5").disabled = true;
    document.getElementById("first_name_domain5").value = "";
    document.getElementById("last_name_domain5").value = "";
    document.getElementById("email_domain5").value = "";
    document.getElementById("phone_domain5").value = "";
    document.getElementById("position_domain5").value = "";
    document.getElementById("role_domain5").value = "Role";
  }
}



</script>

CodePudding user response:

The problem is function_name is a string, rather than the reference to a function.

May I propose you do the following.

const switch_for_dom1 = function () { }

const switch_for_dom2 = function () { }

etc.

Then in

function create_table(domains_names){

   .
   .
   .
   let dom_functions = [switch_for_dom1,switch_for_dom2,....];

   // Next we need to create event listeners to make the toggles usables
   for(var i = 0; i < domains_count; i  ){
     let number = i 1;
     let domain_toggle = `domain${number}`;
     let function_name = dom_functions[i];
 document.getElementById(domain_toggle).addEventListener("click",function_name);
  }

}
  • Related