Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > JavaScript: Общие вопросы > Клонирование нод с заменой атрибутов


Автор: dm9 2.10.2007, 12:51
Добрый день.

Мне необходимо решить следующую задачу: клонирование ноды со всеми потомками с последующей подменой атрибутов name и id всех этих потомков. Если более широко описывать задачу, есть некоторый набор параметров (input-ов), которые описывают некоторый документ. Необходимо на одной странице дать пользователю возможность создания любого количества таких документов. При этом все документы находятся в одной форме, и при сабмите input-ы разных документов должны отправиться на сервер, очевидно, с разными именами (префиксами).

Есть несколько вариантов.
1. Использование готового решения. Подскажете, какого?
2. Рекурсивное клонирование через DOM. Есть ли здесь подводные камни?
3. Работа через innerHTML с заменой атрибутов регулярками ;)

Какой вариант использовали бы Вы, и почему? Возможно, я какого-то варианта ещё не учёл?

AJAX и создание нод заранее прошу не предлагать, интересует чисто клиентское JS-решение. Причина: AJAX для нас слишком дорогой, создание достаточного количества нод заранее (на сервере) уже сделали, генерация получается слишком долгая. smile

Автор: dsCode 2.10.2007, 12:54
третий вариант (т.к. быстрее innerHTML будет работать), но вперемешку со вторым

Автор: dm9 2.10.2007, 13:07
А вперемешку -- это как? Клонируемые ноды должны по вёрстке располагаться одна под другой.

Автор: cruelangel 2.10.2007, 13:11
> очевидно, с разными именами (префиксами)

совершенно не очевидно smile

если на сервере php, то он умеет образовывать массивы из такого:

<input name="name[]" value="a" />
<input name="name[]" value="b" />
<input name="name[]" value="c" />

если что-то другое, то нужно парсить post-данные руками.

Автор: smartov 2.10.2007, 13:28
dm9, у меня была такая задача.
Я использовал вариант 2, потому что он наиболее контролируемый. 

Делал так.

Был "шаблон" того, что надо клонировать, с id-шками полей например name, surname, address и именами полей формата name="address[]" - то есть чтобы приходило массивом.
Типа такого
Код

<!-- template -->
<table id="template">
<tr>
    <td><input type="text" name="name[]" id="name" /></td>
</tr>
<tr>
    <td><input type="text" name="address[]" id="address" /></td>
</tr>
</table>


Все id нужных полей лежат в массиве например dynamicFields.
Так-же была переменка счетчик, для того чтобы новые id делать уникальными.
Код

var dynamicFields_types = new Array('text', 'text');
var dynamicFields_names = new Array('name', 'address');
var counter = 1;


Так же я написал (по быстрому) функцию поиска заданного child-a по имени тега и id
Код

/**
 * Возвращает ссылку на child-a ноды tparent  с именем тега tagName и заданным id
 *
 */
function getSubelementByTagAndId(tparent, tagName, id) {
    if (tparent == null)
        return;

    if (id == null || !id)
        return tparent.getElementsByTagName(tagName)[0];

    for (var i=0; tparent.getElementsByTagName(tagName)[i]; i++) {
        if (tparent.getElementsByTagName(tagName)[i].id == id)
            return tparent.getElementsByTagName(tagName)[i];
    }
    
    return null;
}


Когда надо было создать новую копию, я делал 
1) клон с "шаблона" (cloneNode и до поры не делал appendChild)
2) использовал getSubelementByTagAndId чтобы найти всех детей клона (благо список кого искать у нас в массиве)
3) заменял всем детям id с оригинального на id+'_'+counter (то есть получалось типа name_1 ...)
4) counter++

FAQ:
1) Почему не использовал getElementById думаю ясно - сразу после клонирования он будет возвращать неверный результат.
2) Почему функция getSubelementByTagAndId написана так, что требует еще тип тега - потому что внутри использует getElementsByTagName, можно переписать на пробег по всем child-aм самостоятельно, но это будет работать медленнее, зато не нужно будет передавать тип тега.

Добавлено @ 13:32
На счет перемешки.

Цитата(dm9 @  2.10.2007,  12:07 Найти цитируемый пост)
А вперемешку -- это как? Клонируемые ноды должны по вёрстке располагаться одна под другой. 


Я так понимаю товарищ предлагает склонировать ноду используя cloneNode а дальше не искать child-ов, а сделать replace в innerHTML нужных подстрок.
Лично я считаю такой вариант опасным, потому что можно ненароком что-то забыть и заменяться будет не то, что нужно

Автор: dsCode 2.10.2007, 13:52
smartov, 
Цитата(smartov @  2.10.2007,  13:28 Найти цитируемый пост)
Я так понимаю товарищ предлагает склонировать ноду используя cloneNode а дальше не искать child-ов, а сделать replace в innerHTML нужных подстрок.
Лично я считаю такой вариант опасным, потому что можно ненароком что-то забыть и заменяться будет не то, что нужно

вполне, может быть и опасным (в конкретной реализации), я вообще отстраненно сказал, из расчета оптимизации по скорости. Создание элементов через DOM, на мой взгляд, тоже более красивое и удобо-редактируемое в дальнейшем. Но innerHTML будет работать быстрее (особенно, если его не конкатенатить (строку собирать), а писать сначала части в массив, а потом join('') сделать - самый быстрый вариант). Но DOM, повторю, мне кажется более гибким и в каких-то реализациях - более правильным даже (хоть он и медленней).

Автор: Се ля ви 2.10.2007, 16:33
Второй. Думаю, камней особых не будет, если грамотно написать - но в тебе я не сомневаюсь smile

Добавлено через 7 минут и 19 секунд
Вот! Как раз как smartov советует smile

Автор: dm9 4.10.2007, 16:08
smartov, спасибо большое.
Попробую сделать именно так.

Меня больше всего смущало как раз (временное) наличие одинаковых идентификаторов. А это нигде ошибок в консоль не бросает?

Автор: smartov 4.10.2007, 17:52
dm9, 
Цитата(dm9 @  4.10.2007,  15:08 Найти цитируемый пост)
А это нигде ошибок в консоль не бросает?

Попробуй - узнаешь smile Совсем девелоперы обленились smile
У меня не бросало. Потому что в этом ничего такого нет. Можешь попробовать сделать просто страничку с двумя элементами с одинаковым id и проверить что будет. Чаще всего просто ничего не вернется по getElementById, в остальном от браузера зависит - undefined behavior в общем, но не ошибка.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)