简体   繁体   中英

Clone Table Row with Bootstrap Selectpicker with Filter

I have a Laravel application using Bootstrap. I have a form (shown below) where I want to add more rows (via JS) by clicking the Add Row button. I have a Select/Selectpicker ("Opponent") that I want to be able to type and live filter to find the right option.

The Selectpicker works fine in row 1. However, when I clone the row, the Selectpicker does 2 weird things: (1) The new Select loses all its options, so there is nothing to choose from, and (2) It retains the selected value of the cloned element instead of clearing like the rest of the inputs.

Note: In the HTML code below, you'll see a commented-out Select for a static Select that does NOT use filtering. This works perfectly fine; clones successfully, clears the value, and has all the options in the drop-down. Only the Selectpicker has issues cloning.

我要复制的表格行

JavaScript function:

<script>
  function cloneRow() {

    var table = document.getElementById("gameBody"); // find table to append to
    var count = table.rows.length + 1;
    var gameStr = "game";
    var oppString = "opponent";

    var row = document.getElementById("game1"); // find row to copy

    var clone = row.cloneNode(true); // copy children too
    clone.id = gameStr + count; // change id of new row

    table.appendChild(clone); // add new row to end of table

    // Clear fields in new row
    var newRow = document.getElementById(gameStr.concat(count));
    inputs = newRow.getElementsByTagName('input');
    for (index = 0; index < inputs.length; ++index) {
      if(inputs[index].type == "text" || inputs[index].type == "date")
        inputs[index].value = '';
    }
  }
</script>

CSS/JS includes:

<!-- Inside the Head tag -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.18/dist/css/bootstrap-select.min.css">

<!-- At the bottom of the Body -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/js/bootstrap4-toggle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.18/dist/js/bootstrap-select.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.18/dist/js/i18n/defaults-*.min.js"></script>

HTML table:

<table class="table table-sm table-striped" id="game_table">
  <thead>
    <tr>
      <th>Date*</th>
      <th>Opponent</th>
      <th>Name Override</th>
      <th>Location*</th>
      <th>Site Name</th>
      <th>Game Type*</th>
    </tr>
  </thead>
  <tbody id="gameBody">
    <tr class="dummy-row" id='game1'>

      <!-- Date -->
      <td>
        <input type="date" name='gameDate[]' id="gameDate1" class="form-control" required/>
      </td>

      <!-- Opponent -->
      <td>
        <select name='opponent[]' id="opponent1" class="selectpicker form-control" data-live-search="true" title="Select an opponent" data-hide-disabled="true">
        <!--<select name='opponent[]' class="form-control"title="Select an opponent">-->
          <option value="">Select a Team</option>
            @foreach($allschools as $school)
              <option value="{{ $school->id }}">{{ isset($school->nickname) ? $school->nickname : $school->name }}
              @if($school->name != $school->city)
                ({{ $school->city }})
              @endif
              </option>
            @endforeach
        </select>
      </td>

      <!-- Opponent Override -->
      <td>
        <input type="text" name='opponentOverride[]' id="opponentOverride1" class="form-control"/>
      </td>

      <!-- Location -->
      <td>
        <select name='location[]' id="location1" class="form-control" required>
          <option value="HOME">Home</option>
          <option value="AWAY">Away</option>
        </select>
      </td>

      <!-- Site Name -->
      <td>
        <input type="text" name='site[]' id="site1" class="form-control"/>
      </td>

      <!-- Game Type -->
      <td>
        <select name='gameType[]' id="gameType1" class="form-control" required>
          <option value="REGULAR SEASON">Reg. Season</option>
          <option value="POSTSEASON">Postseason</option>
          <option value="SCRIMMAGE">Scrimmage</option>
        </select>
      </td>
    </tr>
  </tbody>
</table>

<table class="table tabls-sm table-borderless">
  <tr>
    <td class="text-left" width="50%">
      <a id='add_row' onclick="cloneRow()" class="btn btn-sm btn-warning">Add Row</a>
    </td>
    <td class="text-right" width="50%">
      <a id='delete_row' onclick="deleteLastRow()" class="btn btn-sm btn-danger">Delete Last Row</a>
    </td>
  </tr>
</table>

Thank you for your help!

I figured it out using this as a blueprint: Add Row dynamically with SelectPicker

At a high level, this is what I had to do:

  1. Remove the "selectpicker" class from the Selectpicker ("Opponent")
  2. In the add_row() function, initialize the Selectpicker class
  3. Dynamically append the resulting HTML as the new row

I guess it comes down to how Bootstrap treats the Selectpicker class. I don't fully understand it, but the best I can explain is... When you use <select class="selectpicker"... Bootstrap changes the object so that it is no longer a pure Select with options belonging to it. Rather, it wraps it in other, dynamically-created layers on-the-fly (div=>select=>button=>div=>options, etc). This causes issues when cloning because the object you're cloning (the Select) no longer contains those Options, as they are lost somewhere else in the hierarchy (for lack of better terms). I remember reading that in another post, but didn't really get it until now (kinda).

Here is my functioning code:

HTML Table:

<table class="table table-sm table-striped" id="gameTable">
  <thead>
    <tr>
      <th>Date*</th>
      <th>Opponent</th>
      <th>Name Override</th>
      <th>Location*</th>
      <th>Site Name</th>
      <th>Game Type*</th>
    </tr>
  </thead>
  <tbody id="gameBody">
    <tr id="gameRow">

      <!-- Date -->
      <td>
        <input type="date" name='gameDate[]' id="gameDate1" class="form-control" required/>
      </td>

      <!-- Opponent -->
      <td>
        <select name='opponent[]' id="opponent1" class="form-control" data-live-search="true" title="Select an opponent" data-hide-disabled="true">
        <!--<select name='opponent[]' class="form-control" title="Select an opponent">-->
          <option value="">Select a Team</option>
            @foreach($allschools as $school)
              <option value="{{ $school->id }}">{{ isset($school->nickname) ? $school->nickname : $school->name }}
              @if($school->name != $school->city)
                ({{ $school->city }})
              @endif
              </option>
            @endforeach
        </select>
      </td>

      <!-- Opponent Override -->
      <td>
        <input type="text" name='opponentOverride[]' id="opponentOverride1" class="form-control"/>
      </td>

      <!-- Location -->
      <td>
        <select name='location[]' id="location1" class="form-control" required>
          <option value="HOME">Home</option>
          <option value="AWAY">Away</option>
          <!--<option value="NEUTRAL">Neutral</option>-->
        </select>
      </td>

      <!-- Site Name -->
      <td>
        <input type="text" name='site[]' id="site1" class="form-control"/>
      </td>

      <!-- Game Type -->
      <td>
        <select name='gameType[]' id="gameType1" class="form-control" required>
          <option value="REGULAR SEASON">Reg. Season</option>
          <option value="POSTSEASON">Postseason</option>
          <option value="SCRIMMAGE">Scrimmage</option>
        </select>
      </td>

    </tr>
  </tbody>
</table>

<table class="table tabls-sm table-borderless">
  <tr>
    <td class="text-left" width="30%">
      <a id='add_row' onclick="add_row()" class="btn btn-sm btn-warning">Add Row</a>
    </td>
    <td class="text-center" width="40%">
      <button type="submit" class="btn btn-primary">Create Games</button>
    </td>
    <td class="text-right" width="30%">
      <a id='delete_row' onclick="deleteLastRow()" class="btn btn-sm btn-danger">Delete Last Row</a>
    </td>
  </tr>
</table>

Function (bottom of Body):

<script>
  var cloned = $("#gameTable tbody tr:first").clone() //keep clone for later use..
  $("select[name*=opponent]").selectpicker() //intialize your slectpicker
  function add_row() {
    $(cloned).find("input").val("") //empty any input..
    $("<tr>" + $(cloned).html() + "</tr>").appendTo($("#gameTable tbody")) //append to your tbody..
    $("#gameTable tbody tr:last select").selectpicker() //intialize newly added selct...
  }
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM