javascriptdom-eventsmaterial-design-lite

Javascript execution failed on elements which were added later through Javascript


In a project currently I'm working on, There are many items for which a dialog has to be opened. For each new dialog, data inside changes and that I have done using Javascript. Now If I add any elements like say a checkbox to the dialog from Javascript, The material js is not working on it. So I Checked a similar issue and got an answer, which I have implemented and still doesn't work. In this snippet I have made a similar situation. An Add Button is used to add to the dialog and when Dialog opens the checkbox doesn't behave as it was in dialog during page load. To show this I have added a Checkbox before itself, not from Javascript. After adding Checkbox from Javascript the old existing checkbox also doesn't work.

Please help me, it'll be of great help.

function resetJs(path) {
  var scripts = document.getElementsByTagName('script'),
    newScript = document.createElement("script");

  newScript.src = path + "?timestamp=" + Math.round(new Date().getTime() / 1000);

  for (var i = 0; i < scripts.length; ++i) {
    var srcUrl = scripts[i].getAttribute('src');
    if (srcUrl && srcUrl.indexOf(path) > -1) {
      scripts[i].parentNode.replaceChild(newScript, scripts[i]);
    }
  }
}
var dialog = document.querySelector('dialog');

var addData = document.querySelector('#add');
addData.addEventListener('click', function() {
  var data = document.querySelector('#dialogContent');
  data.innerHTML += '<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-1"><input type="checkbox" id="checkbox-1" class="mdl-checkbox__input" checked><span class="mdl-checkbox__label">Checkbox From JS</span></label>';

});



var showDialogButton = document.querySelector('#show-dialog');
if (!dialog.showModal) {
  dialogPolyfill.registerDialog(dialog);
}
showDialogButton.addEventListener('click', function() {

  dialog.showModal();
  resetJs('https://code.getmdl.io/1.3.0/material.min.js');
});
dialog.querySelector('.close').addEventListener('click', function() {
  dialog.close();
});
<link href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css" rel="stylesheet"/>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<button id="show-dialog" type="button" class="mdl-button">Show Dialog</button>
<button id="add" type="button" class="mdl-button">Add</button>
<dialog class="mdl-dialog">
  <h4 class="mdl-dialog__title">Allow data collection?</h4>
  <div class="mdl-dialog__content" id="dialogContent">
    <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-1"><input type="checkbox" id="checkbox-1" class="mdl-checkbox__input" checked><span class="mdl-checkbox__label">Checkbox Added Before</span></label>
    <p>
      Allowing us to collect data will let us get you the information you want faster.
    </p>
  </div>
  <div class="mdl-dialog__actions">
    <button type="button" class="mdl-button">Agree</button>
    <button type="button" class="mdl-button close">Disagree</button>
  </div>
</dialog>


Solution

  • From the docs of mdl here

    Material Design Lite will automatically register and render all elements marked with MDL classes upon page load. However in the case where you are creating DOM elements dynamically you need to register new elements using the upgradeElement function.

    So, what you can do is in your addData function;

    var addData = document.querySelector("#add");
      addData.addEventListener("click", function() {
        var data = document.querySelector("#dialogContent");
        var label = document.createElement("label");
        label.className = "mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect";
        label.innerHTML =
          '<input type="checkbox" id="checkbox-1" class="mdl-checkbox__input" checked><span class="mdl-checkbox__label">Checkbox From JS</span>';
        label.htmlFor = "checkbox-1";
        componentHandler.upgradeElement(label);
        data.appendChild(label);
      });
    
    

    You need to use componentHandler.upgradeElement to upgrade your dynamically created element into material element and then append the child to data.

    Please take a look at this codesandbox