HTML-формы jQuery .clone(), которые содержат переключатели — сохраняйте радио-события, специфичные для клонированных элементов.

Я работаю над некоторыми внешними формами, используя Bootstrap, jQuery, HTML и серверную часть Django. В какой-то момент в форме пользователь должен добавить информацию «Программное обеспечение», а затем иметь возможность загрузить файл программного обеспечения или использовать URL-адрес своего размещенного файла. Параметр URL позволяет использовать несколько URL-адресов, из которых можно загрузить файл. Существует также возможность добавления нескольких пакетов программного обеспечения, поэтому, если они хотят добавить еще один, есть кнопка «Добавить», которая клонирует группы форм и позволяет пользователю вводить информацию для другого пакета программного обеспечения.

Я не уверен, как сделать это динамическим, когда клонированные данные получат свои собственные значения ключей для использования в бэкэнде, но на данный момент моя самая большая проблема заключается в том, что когда вы нажимаете кнопку Add More Software..., клонированные переключатели влияют только на оригинальные переключатели, и к ним не привязаны события .switchClass() для изменения их внешнего вида. Я не могу на всю жизнь понять, как заставить переключатели быть привязанными к HTML, с которым они клонируются. Я прикрепил jsfiddle для просмотра:

клон jQuery() и переключатели

Мой вопрос заключается в том, как сделать это более динамичным, чтобы кнопки работали с HTML, который клонируется вместе с переключателями, и как настроить динамические группы клонированных форм для захвата значений на бэкэнде?

<div class="software-container">
<div class="form-group">
    <label class="col-sm-2 control-label">
      * Files
    </label>
    <div class="col-sm-9">
      <div class="btn-group" data-toggle="buttons">
        <label id="software-upload-btn" for="software-upload" class="btn btn-default">
          <input id="software-upload" type="radio" name="software-upload" value="upload"> Upload
        </label>
        <label id="software-url-btn" for="software-upload" class="btn btn-default">
          <input id="software-url" type="radio" name="software-url" value="url"> URL
        </label>
      </div>
    </div>
  </div>
  <div id="software-upload-panel" class="hidden">
    <div class="form-group upload-container">
      <div class="col-sm-offset-2 col-sm-9">
        <input type="file" id='software-file' name="software-file" title="" placeholder="No File">
      </div>
    </div>
  </div>

  <div id="software-url-panel" class="hidden">
    <div class="form-group url-container">
      <div class="col-sm-offset-2 col-sm-9">
        <input type="url" id="software-file" name="software-file" class="form-control" placeholder="https://www.example.com/my-software-4.6.tar.gz" title="">
        <button class="close hidden" type="button">x</button>
      </div>
    </div>
    <div class="form-group add-url-container">
      <div class="col-sm-offset-2 col-sm-9">
        <button class="add-url btn btn-default" type="button">
          <i class="glyphicon glyphicon-plus"></i> Add Another URL...
        </button>
      </div>
    </div>
  </div>
</div>

<div class="form-group add-container">
  <label for="add-btn" class="col-sm-2 control-label">
    Add Software:
  </label>

  <div class="col-sm-9">
    <button id="add-software-btn" class="btn btn-default" type="button">
      <i class="glyphicon glyphicon-plus"></i> Add More Software...
    </button>
  </div>
</div>

И мой js:

$(document).ready(function() {
  // Actions for URL/Upload button options
  $('#software-upload-btn').click(function() {
    if ($('.active')) {
      $('#software-upload-btn').switchClass('btn-default', 'btn-info', 0);
      $('#software-upload-panel').removeClass('hidden');
      $('#software-url-btn').switchClass('btn-info', 'btn-default', 0);
      $('#software-url-panel').addClass('hidden');
    }
  });

  $('#software-url-btn').click(function() {
    if ($('.active')) {
      $('#software-url-btn').switchClass('btn-default', 'btn-info', 0);
      $('#software-url-panel').removeClass('hidden');
      $('#software-upload-btn').switchClass('btn-info', 'btn-default', 0);
      $('#software-upload-panel').addClass('hidden');
    }
  });

  // Add button actions
  $(document).on('click', '.add-url:last', function() {
        $('.url-container:first').clone().insertAfter($('.url-container:last'))
            .find('.close').removeClass('hidden');

        $('.close').click(function() {
            $(this).closest('div.url-container').remove();
        });
    });

  $(document).on('click', '#add-software-btn:last', function() {
    $('.software-container:first').clone(true)
      .insertAfter($('.software-container:last'));
  });
});

person Charles Williams    schedule 19.01.2016    source источник
comment
Потому что id должны быть уникальными. Так что селекторы не работают.   -  person rrk    schedule 19.01.2016
comment
Хорошо @RejithRKrishnan, это имеет абсолютный смысл. Не знаю, почему я этого еще не видел. Я сначала проверю это и дам вам знать. Надеюсь, это что-то настолько простое.   -  person Charles Williams    schedule 19.01.2016
comment
Хорошо, @RejithRKrishnan, теперь вместо переключателей загрузки и URL-адреса меняются только предварительные / исходные переключатели, он меняет их все, когда я делаю их классами. Итак, я предполагаю, что именно здесь появляется динамическая часть. Но я не уверен, как это сделать с jQuery clone() и как лучше всего заставить эти кнопки работать только с их клонированными панелями/контейнерами.   -  person Charles Williams    schedule 19.01.2016
comment
Можете ли вы добавить последнюю скрипку?   -  person rrk    schedule 19.01.2016
comment
@RejithRKrishnan ~ jsfiddle.net/charlwillia6/tavjepdb/16   -  person Charles Williams    schedule 19.01.2016


Ответы (1)


ОБНОВИТЬ

Хорошо, я внес некоторые изменения, чтобы показать вам силу this:

  • Добавлены специальные классы для 2 кнопок: .uplBtn и .urlBtn
  • Добавлен .software-container класс в #software-container-1
  • var con = $(this).closest('.software-container'); This is how each software-container is isolated.
    • $(this) is that specific button that was just clicked.
    • .closest('.software-container') начнется с $(this) и будет идти до .software-container.
  • var pkg = $('#' + con.attr('id')); это некрасиво, но работает. Это объединит строку .software-container id и превратит ее в объект jQuery.

Теперь, когда вы нажимаете кнопку, она открывает только ту панель, которую должна была открыть. Кстати, есть побочный эффект клонирования, если вы заметили, новые клоны будут начинаться со скрытого или скрытого состояния в соответствии с состоянием клона перед ним. Возможно, вам следует создать шаблон #software-container-0, который никто не увидит и не тронет. Или, может быть, просто сбросить скрытые классы на новом клоне только один раз.

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>34884672</title>
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
  <link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
  <style>
  </style>
</head>

<body>
  <div id="software-container-1" class="software-container">
    <div class="form-group">
      <label class="col-sm-2 control-label">
        * Files
      </label>
      <div class="col-sm-9">
        <div class="btn-group" data-toggle="buttons">
          <label for="software-upload-btn" class="btn uplBtn btn-default">
            <input class="software-upload-btn" type="radio" name="software-upload" value="upload">Upload
          </label>
          <label for="software-url-btn" class="btn urlBtn btn-default">
            <input class="software-url-btn" type="radio" name="software-url" value="url">URL
          </label>
        </div>
      </div>
    </div>
    <div class="software-upload-panel hidden">
      <div class="form-group upload-container">
        <div class="col-sm-offset-2 col-sm-9">
          <input type="file" class='software-upload-file form-control' name="software-upload-file" title="" placeholder="No File">
        </div>
      </div>
    </div>

    <div class="software-url-panel hidden">
      <div class="form-group url-container">
        <div class="col-sm-offset-2 col-sm-9">
          <input type="url" class="software-url-file form-control" name="software-url-file" placeholder="https://www.example.com/my-software-4.6.tar.gz" title="">
          <button class="close hidden" type="button">x</button>
        </div>
      </div>
      <div class="form-group add-url-container">
        <div class="col-sm-offset-2 col-sm-9">
          <button class="add-url btn btn-default" type="button">
            <i class="glyphicon glyphicon-plus"></i> Add Another URL...
          </button>
        </div>
      </div>
    </div>
  </div>

  <div class="form-group add-container">
    <label class="col-sm-2 control-label">
      Add Software:
    </label>

    <div class="col-sm-9">
      <button class="add-software-btn btn btn-default" type="button">
        <i class="glyphicon glyphicon-plus"></i> Add More Software...
      </button>
    </div>
  </div>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
  <script>
    $(document).ready(function() {
      // Actions for URL/Upload button options
      $('label.uplBtn').click(function(event) {
        var con = $(this).closest('.software-container');
        var pkg = $('#' + con.attr('id'));
        console.log('pkg: ' + pkg);
        $(this).switchClass('btn-default', 'btn-info', 0).addClass('active');
        pkg.find('.software-upload-panel').removeClass('hidden');
        pkg.find('label.urlBtn').switchClass('btn-info', 'btn-default', 0).removeClass('active');
        pkg.find('.software-url-panel').addClass('hidden');

        event.stopPropagation();
      });

      $('label.urlBtn').click(function(event) {
        var con = $(this).closest('.software-container');
        var pkg = $('#' + con.attr('id'));
        console.log('pkg: ' + pkg);
        $(this).switchClass('btn-default', 'btn-info', 0).addClass('active');
        pkg.find('div.software-url-panel').removeClass('hidden');
        pkg.find('label.uplBtn').switchClass('btn-info', 'btn-default', 0).removeClass('active');
        pkg.find('div.software-upload-panel').addClass('hidden');

        event.stopPropagation();
      });

      // Add button actions
      $(document).on('click', '.add-url:last', function() {
        $('div[id^="url-container"]:first').clone().insertAfter($('div[id^="url-container"]:last'))
          .find('.close').removeClass('hidden');

        $('.close').click(function() {
          $(this).closest('div[id^="url-container"]').remove();
        });
      });

      $(document).on('click', '.add-software-btn:last', function() {
        var $div = $('div[id^="software-container"]:last');
        var num = parseInt($div.prop("id").match(/\d+/g), 10) + 1;
        var $software_container = $div.clone(true, true).prop('id', 'software-container-' + num);
        $div.after($software_container);

      });
    });
  </script>
</body>

</html>

Я думаю, вы хотели клонировать #software-container и дать каждому уникальный идентификатор, чтобы вы могли подключить их из бэкэнда. Отталкиваясь от недавней скрипки, вот что я получил: https://jsfiddle.net/zer00ne/oay1zbva/

Я не уверен, что вы хотели .clone(true), но я помню, что вы хотели сохранить события...?

изменение jQuery

  $(document).on('click', '.add-software-btn:last', function() {
    var $div = $('div[id^="software-container"]:last');
    num = parseInt($div.prop("id").match(/\d+/g), 10);
    num++;
    //var $software_container = $div.clone().prop('id', 'software-container-'+num);
    //$div.after($software_container);
    $('.software-container:last').clone(true).insertAfter($('.software-container:last')).prop('id', 'software-container-' + num);;
  });
});
person zer00ne    schedule 19.01.2016
comment
И я думаю, что это определенно на правильном пути. Но если вы проверите и свою скрипку, и мою, то, когда вы нажимаете кнопки Upload и URL, они все равно каким-то образом соединяются, и они не должны быть связаны. Поэтому я думаю, наряду с тем, что вы добавили, что-то вроде: $software_container.find('div[id^="software-upload-btn"]'+num).attr('for', 'software-upload'+num); это должно быть добавлено для каждой кнопки и панели, чтобы сделать их также уникальными. - person Charles Williams; 19.01.2016
comment
Да, выглядит нормально, если вы используете счетчик var num (к сведению, он глобальный, так что имейте в виду). Просто подумав вслух, вы могли бы использовать $(this) и создать другие классы идентификаторов. - person zer00ne; 19.01.2016
comment
@CharlWillia6 В любом случае, дайте мне знать, если вам нужен еще совет, и не забудьте проголосовать и/или принять ;-) - person zer00ne; 19.01.2016
comment
~ Я изменил все идентификаторы на классы, и это не решает проблему. Я использую скрытые div, активируемые этими переключателями, поэтому каждый переключатель должен быть прикреплен к уникальной панели/контейнеру, я думаю, чтобы это работало. В противном случае каждая кнопка управляет всеми остальными кнопками перед ней. - person Charles Williams; 19.01.2016
comment
Хорошо, тогда идентификаторы для них, вероятно, лучший способ. - person zer00ne; 19.01.2016
comment
Но если вы используете $(this) при обращении к его дочерним элементам, его следует изолировать. var rad1 = $(this).find(".software-upload-btn"); должно работать. или var rad1 = $(event.target).find(".software-upload-btn") Имейте это в виду как возможную альтернативу. - person zer00ne; 19.01.2016
comment
@CharlWillia6 Смотрите обновление. Я перестал использовать jsFiddle, потому что он получал устаревший кеш. Новая работающая демонстрация находится во фрагменте. - person zer00ne; 20.01.2016