cloning "rows" of a form with inner functions

37 Views Asked by At

im trying to make dynamic form with inner functions...

I have a template like:

``<div class="polozky row col-12" id="polozky">
                <div class="polozka row col-12 card-footer bg-yellow" id="sablona">

                  <div class="col-md-1.5">
                    <div class="form-group">
                      <label><input type="hidden" name="policko0[]"></label>
                    </div>
                  </div>

                  <div class="col-md-1.5">
                    <div class="form-group">
                      <label>Pořadí: <input type="number" class="inputPoradi" required name="policko1[]" tabindex="1" placeholder="" value="<?php echo $posledniVPoradi + 1; ?>" min="1"></label>
                    </div>
                  </div>


                 

                  <div class="col-md-2">
                    <div class="form-group">
                      <label>Typ: </label>
                      <select class="col-md-7" name="typ[]" id="sem" tabindex="3" onchange="javascript: dynamicdropdown(this.options[this.selectedIndex].value);">
                      <option selected>Choose...</option>
                        <option value="1" <?php /* echo ($result['Typ'] == '1' ? 'selected' : '') */ ?>>Oddělení</option>
                        <option value="2" <?php /*echo ($result['Typ'] == '2' ? 'selected' : '')*/ ?>>Skupina</option>
                        <option value="3" <?php /*echo ($result['Typ'] == '3' ? 'selected' : '')*/ ?>>Položka</option>
                        <option value="4" <?php /*echo ($result['Typ'] == '4' ? 'selected' : '')*/ ?>>Vlastní sleva</option>
                      </select>
                    </div>
                  </div>

                  <div class="col-md-3">
                    <div class="form-group">
                      <label>Název:</label>
                      <select class="form-select" id="Sub1" required>
                        <option selected>Choose...</option>
                        <option value="sub1">Applied Maths-1</option>
                        <option value="sub2">Applied Physics-1</option>
                        <option value="sub3">Applied Physics-2</option>

                      </select>
                    </div>
                  </div>





                  <button class="col-md-1 form-group btn btn-block btn-danger odebrat" onclick="odebrat(this)">× Odebrat</button>


                  <div class="col-md-1">
                    <div class="form-group">
                      <button class="btn btn-block btn-success" type="button" onclick="pridatPole()" tabindex="1">+ Přidat</button>
                    </div>
                  </div>

                </div>
              </div>`

and the "template row" can be clone with this:

`<script>
  var prvniPolozka = document.getElementById('sablona');
  var sablona = prvniPolozka.cloneNode(true);
  var indexPoradi = (2 + <?php echo $posledniVPoradi; ?>);


  function indexPlusJedna() {
    indexPoradi++;
  }

  function pridatPole() {

    var kopie = sablona.cloneNode(true);
    document.getElementById('polozky').appendChild(kopie);
    kopie.getElementsByTagName("input")[0].focus();
    kopie.getElementsByTagName("input")[1].value = indexPoradi;
    indexPlusJedna();
  }

  function odebrat(el) {
    var polozka = el.parentNode;
    polozka.parentNode.removeChild(polozka);

  }
</script>`

my problem is that I want to have on the every "template row" 2 select inputs... which the first one determines options what i see in the second SELECT input... the function:

` function dynamicdropdown(n) {
                      var arr1 = ["oddělení 1", "oddělení 2"];
                      var arr2 = ["skupina 1", "skupina 2"];
                      var arr3 = ["polozka 1", "polozka 2"];
                      var arr4 = ["sleva 1", "sleva 2"];
                      if (n === "1") {
                        document.getElementById('Sub1').innerHTML = '';
                        for (var i = 0; i < arr1.length; i++) {
                          document.getElementById('Sub1').innerHTML += "<option>" + arr1[i] + "</option>";

                        }
                      } else if (n === "2") {
                        document.getElementById('Sub1').innerHTML = '';
                        for (var i = 0; i < arr2.length; i++) {
                          document.getElementById('Sub1').innerHTML += "<option>" + arr2[i] + "</option>";
                        }
                      }
                      else if (n === "3") {
                        document.getElementById('Sub1').innerHTML = '';
                        for (var i = 0; i < arr3.length; i++) {
                          document.getElementById('Sub1').innerHTML += "<option>" + arr3[i] + "</option>";
                        }
                      } else if (n === "4") {
                        document.getElementById('Sub1').innerHTML = '';
                        for (var i = 0; i < arr4.length; i++) {
                          document.getElementById('Sub1').innerHTML += "<option>" + arr4[i] + "</option>";
                        }
                      }

                    }`

now it works only in the first row... I know that i cannot us getElementById and the id in html inputs... This was just used for the examle...

How to do it? Thanks for help. M.

1

There are 1 best solutions below

0
Professor Abronsius On

I think I understood your question and code correctly and hope that the following might be helpful. In most instances ID attributes when generating dynamic content are more trouble than they are worth ( as the expression goes ) - you are better using events to identify DOM elements and from the event.target &/or event.currentTarget you can then use other selectors (parent,child,sibling) to further traverse the DOM.

Rather than using inline event handlers ( and you were having issue with one of those anyway ) you can use delegated event listeners bound to a parent element ( in this case the document itself ) and, as mentioned, use the event to identify the element that invoked the event. From that point the various functions for adding,cloning and deleting should be modified to work with the event.target and parentNode / childNodes.

I modified very little of the original HTML ( added new class to the buttons - XBTN, modified IDs to become data-id values and removed the PHP only for the demo. The only element that still has an ID is the main parent element, id='polozky' - everything else uses dataset attributes instead.

document.addEventListener('change', e => {
  if (e.target instanceof HTMLSelectElement && e.target.dataset.id == 'sem') {
    const args = [
      ["oddělení 1", "oddělení 2"],
      ["skupina 1", "skupina 2"],
      ["polozka 1", "polozka 2"],
      ["sleva 1", "sleva 2"]
    ];
    let key = e.target.value - 1;
    let data = args[key];

    let oSelSub = e.target.closest('[data-id="sablona"]').querySelector('[data-id="Sub1"]');
        oSelSub.innerHTML = '';
        data.forEach( item=>{
          oSelSub.appendChild(new Option( item, item ));
        });
  }
});


document.addEventListener('click', e => {
  if (e.target instanceof HTMLButtonElement && e.target.classList.contains('XBTN')) {
    switch (e.target.dataset.id) {
      case 'odebrat': odebrat.call(this, e); break;
      case 'pridat': pridatPole.call(this, e); break;
    }
  }
})


var prvniPolozka = document.querySelector('[data-id="sablona"]');
var sablona = prvniPolozka.cloneNode(true);
var indexPoradi = 2;


function pridatPole() {
  let kopie = sablona.cloneNode(true);
      kopie.querySelector('input.inputPoradi').focus();
      kopie.querySelector('input.inputPoradi').value = indexPoradi;
  prvniPolozka.parentNode.appendChild(kopie);
  indexPoradi++;
}

function odebrat(e) {
  let el = e.target.parentNode;
      el.parentNode.removeChild(el);
}
[data-id='sablona'] {
  padding: 1rem;
  border: 1px solid black;
  margin: 1rem
}
<div class="polozky row col-12" id="polozky">
  <div class="polozka row col-12 card-footer bg-yellow" data-id="sablona">

    <div class="col-md-1.5">
      <div class="form-group">
        <label><input type="hidden" name="policko0[]"></label>
      </div>
    </div>

    <div class="col-md-1.5">
      <div class="form-group">
        <label>Pořadí: <input type="number" class="inputPoradi" required name="policko1[]" tabindex="1" value=54 min="1"></label>
      </div>
    </div>

    <div class="col-md-2">
      <div class="form-group">
        <label>Typ: </label>
        <select class="col-md-7" name="typ[]" data-id="sem" tabindex="3">
          <option selected>Choose...</option>
          <option value="1">Oddělení</option>
          <option value="2">Skupina</option>
          <option value="3">Položka</option>
          <option value="4">Vlastní sleva</option>
        </select>
      </div>
    </div>

    <div class="col-md-3">
      <div class="form-group">
        <label>Název:</label>
        <select class="form-select" data-id="Sub1" required>
          <option selected>Choose...</option>
          <option value="sub1">Applied Maths-1</option>
          <option value="sub2">Applied Physics-1</option>
          <option value="sub3">Applied Physics-2</option>

        </select>
      </div>
    </div>

    <button data-id='odebrat' class="XBTN col-md-1 form-group btn btn-block btn-danger odebrat">× Odebrat</button>

    <div class="col-md-1">
      <div class="form-group">
        <button data-id='pridat' class="XBTN btn btn-block btn-success" type="button" tabindex="1">+ Přidat</button>
      </div>
    </div>

  </div>
</div>