Клонирование элемента начальной загрузки с помощью прослушивателя событий
Я пытаюсь клонировать элемент начальной загрузки, который имеет поведение переключения данных, предоставляемое bootstrap:
HTML
<div class="container">
<button aria-expanded="false" data-target="#collapsible_obj_0" data-toggle="collapse" class="btn btn-link collapsed">click here</button>
<div style="height: 0px;" aria-expanded="false" id="collapsible_obj_0" class="collapse">
<span>foo</span>
</div>
</div>
После клонирования я меняю ID
div на новый уникальный id, а кнопка data-target
кнопки указывает на новый div,
JS
var header = objectContainer.clone(true);
var counter = this.collapsibleObjCounter++;
var collapseId = "collapsible_obj_" + counter;
header.find(".collapse").attr("id", collapseId);
header.find("button[data-toggle='collapse']").attr("data-target", "#"+collapseId);
Кнопка и div являются дочерними элементами контейнера объектов. Я клонирование.
Иногда это работает, но иногда я получаю кнопку, которая все еще расширяет и сжимает оригинальный div, даже если при проверке HTML идентификаторы выглядят правильно.
Я подозреваю, что обработчик события, который скопирован, может быть жестким кодированием ссылки на идентификатор div, который нужно развернуть и сжать, поэтому просто исправление идентификаторов в элементах DOM не работает. Однако это не объясняет, почему некоторые из клонов работают, а другие нет.
Каков правильный способ клонирования того, к чему привязаны загрузочные поведения?
Итак, в нескольких ответах указано, что просто удаление true
из моего вызова clone()
позволит избежать копирования прослушивателя событий. Поэтому я теперь понимаю, что моя проблема немного сложнее, чем тот, который я упростил здесь. Я задам его как отдельный вопрос. (Клонирование элемента Bootstrap, но не всех прослушивателей событий)
Ответы
Ответ 1
Пока ваш код в порядке, просто удалите true
из clone()
ему не нужно.
ОБНОВЛЕНО
Это Boolean указывает, следует ли копировать обработчики событий вместе с элементами. Значение по умолчанию - false. Итак, когда мы вызывали метод .clone()
, не передавая никакого значения Boolean, он просто копировал элементы, но не привязывал к ним обработчики событий. Но когда мы передаем значение true, он копирует как элементы, так и любые обработчики событий, прикрепленные к нему.
Но Bootstrap обрабатывает обработчики событий для динамических объектов, поэтому вам не нужно true
в клоне.
LIKE
Если вы обрабатываете events
для динамических объектов, используя этот способ
$(".btn").click(.....);
// This button was dynamically created and you want a click event for it,
// but it wont work because at the time of event binding this button wasn't exist at all.
НО
Вам необходимо обработать события для динамических объектов, используя технологию делегирования событий.
$(document).on("click",".btn",function(){ .... });
Это будет работать, поскольку обработчик события привязан к элементу выше дерева DOM
(в данном случае, к документу) и будет выполняться, когда событие достигнет этого элемента, возникшего на элементе, соответствующем селектору,
И то, что делает Bootstrap для динамических объектов, также вы делаете то же самое, если это необходимо для динамических объектов. Здесь JSFiddle.
Также вам нужно обернуть целую часть collapsible
в div
для клонирования.
Примечание. Использование .clone()
имеет побочный эффект создания элементов с повторяющимися атрибутами id
, которые должны быть уникальными. Там, где это возможно, рекомендуется избегать клонирования элементов с этим атрибутом или вместо этого использовать атрибуты класса.
Итак, после клонирования вам необходимо обновить атрибут data-target
и div
id, чтобы вновь созданная кнопка targets
вновь созданная панель обвала
Я использую jQuery для него.
Вот код Сниппет
$(function(){
var target = "collapsible_obj_";
var i = 1;
$("#button").click(function(){
$(".parent_colapse:last").clone().insertAfter(".parent_colapse:last");
$(".parent_colapse:last > button").attr("data-target", "#"+target+i);
$(".parent_colapse:last .collapse").attr("id", target+i);
i++;
});
$(document).on("click",".button",function(){
alert();
});
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="parent_colapse">
<button aria-expanded="false" data-target="#collapsible_obj_0" data-toggle="collapse" class="btn btn-link collapsed">click here</button>
<div style="height: 0px;" aria-expanded="false" id="collapsible_obj_0" class="collapse">
<span>foo</span>
<button type="button" class="button">click</button>
</div>
</div>
<button type="button" id="button">Clone</button>
Ответ 2
Не копируйте события во время клонирования, удалите флаг true
.
var header = objectContainer.clone();
Мое предположение: Bootstrap обрабатывает привязку событий к динамическим объектам также для переключения данных, для этого требуется только идентификатор и цель.
Здесь fiddle.
PS: Не знаю, что это было или objectContainer в вопросе OP, поэтому создал закрытие и вставив результат в новую оболочку.
Ответ 3
Я создал JSFiddle вашего кода. Наиболее вероятной ошибкой является то, что вы используете значение this.collapsibleObjCounter++
0
, которое может создать проблему.
Вот рабочий JSFiddle. Пожалуйста, дайте мне знать, если это то, что вы пытаетесь сделать. Спасибо.
https://jsfiddle.net/2fgoywzy/1/
JS
$( document ).ready(function() {
for (i = 1; i < 5; i++) {
var objectContainer = $("#main");
var header = objectContainer.clone(true);
var counter = i; // replace this with this.collapsibleObjCounter++
var collapseId = "collapsible_obj_" + counter;
header.find(".collapse").attr("id", collapseId);
header.find("button[data-toggle='collapse']").attr("data-target", "#"+collapseId);
$(header).appendTo('body');
}
});
HTML
<div id="main">
<button aria-expanded="false" data-target="#collapsible_obj_0" data-toggle="collapse" class="btn btn-link collapsed">click here</button>
<div style="height: 0px;" aria-expanded="false" id="collapsible_obj_0" class="collapse">
<span>foo</span>
</div>
</div>
Если у вас есть значение 0
в this.collapsibleObjCounter++
, я бы предложил сделать ++this.collapsibleObjCounter
. Вместо post increment выполните pre increment
Ответ 4
Проблема не вызвана самими прослушивателями событий. Проблема заключается в том, как работает Bootstrap. Для большинства компонентов Bootstrap Bootstrap создает объект JavaScript, связанный с элементом DOM. Этот объект - это то, что вам нужно позаботиться, когда вы клонируете компоненты Bootstrap. Для элемента collapse
Bootstrap создает collapse
объект.
Объект JavaScript связан с элементом DOM через jQuery $.data
. Это проблема. Если вы используете jQuery clone
и запрашиваете, чтобы обработчики событий были скопированы в клон, вы также получите копию набора данных с помощью $.data
. Однако, когда данные являются ссылкой на объект JavaScript, то это ссылка, которая копируется в клон. Таким образом, оригинал и клон относятся к одному и тому же объекту JavaScript, и здесь все сбивается с пути. Это, кстати, не относится к Bootstrap: любая ссылка подвержена этой проблеме.
Что вы можете сделать, это выполнить $.removeData
для клонированных элементов, которые являются компонентами Bootstrap. Это заставит Bootstrap воссоздать объект JavaScript. Для компонентов, которые автоматически регистрируются в API данных, это должно быть все, что необходимо. (collapse
автоматически регистрируется.) Для компонентов, которые не регистрируются автоматически (например, всплывающих подсказок), вам необходимо вызвать $.[component]
для воссоздания компонента вручную.
Я разворачивал скрипку из aManHasNoName, что иллюстрирует это. Единственными модификациями были:
-
Добавьте параметры true, true
в var header = objectContainer.clone();
-
Измените header.find(".collapse").attr("id", collapseId)
, чтобы добавить .removeData()
в конец.