JQuery клон формы полей и идентификатор приращения - PullRequest
25 голосов
/ 05 ноября 2011

У меня есть блок элементов формы, который я хотел бы клонировать и увеличить их ID, используя метод клонирования jQuery. Я пробовал несколько примеров, но многие из них клонируют только одно поле.

Мой блок структурирован так:

<div id="clonedInput1" class="clonedInput">
  <div>
    <div>
      <label for="txtCategory" class="">Learning category <span class="requiredField">*</span></label>
      <select class="" name="txtCategory[]" id="category1">
        <option value="">Please select</option>
      </select>
    </div>
   <div>
     <label for="txtSubCategory" class="">Sub-category <span class="requiredField">*</span></label>
     <select class="" name="txtSubCategory[]" id="subcategory1">
       <option value="">Please select category</option>
     </select>
   </div>
   <div>
     <label for="txtSubSubCategory">Sub-sub-category <span class="requiredField">*</span></label>
     <select name="txtSubSubCategory[]" id="subsubcategory1">
       <option value="">Please select sub-category</option>
     </select>
   </div>
</div>

Очевидно, что элементы выстроены намного лучше, но вы поняли.

Я хотел бы сохранить структуру идентификатора, то есть category1, subcategory1 и т. Д., Так как я использую их для динамического отображения опций выбора, основанных на родительском выборе, поэтому, если возможно, иметь каждый клонированный блок, например category1 / category2 / category3 и т. Д. .

Ответы [ 4 ]

21 голосов
/ 05 ноября 2011

HTML

<div id="clonedInput1" class="clonedInput">
    <div>
        <label for="txtCategory" class="">Learning category <span class="requiredField">*</span></label>
        <select class="" name="txtCategory[]" id="category1">
            <option value="">Please select</option>
        </select>
    </div>
    <div>
        <label for="txtSubCategory" class="">Sub-category <span class="requiredField">*</span></label>
        <select class="" name="txtSubCategory[]" id="subcategory1">
            <option value="">Please select category</option>
        </select>
    </div>
    <div>
        <label for="txtSubSubCategory">Sub-sub-category <span class="requiredField">*</span></label>
        <select name="txtSubSubCategory[]" id="subsubcategory1">
            <option value="">Please select sub-category</option>
        </select>
    </div>
    <div class="actions">
        <button class="clone">Clone</button> 
        <button class="remove">Remove</button>
    </div>
</div>

JavaScript - Jquery v1.7 и более ранние версии

var regex = /^(.+?)(\d+)$/i;
var cloneIndex = $(".clonedInput").length;

$("button.clone").live("click", function(){
    $(this).parents(".clonedInput").clone()
        .appendTo("body")
        .attr("id", "clonedInput" +  cloneIndex)
        .find("*").each(function() {
            var id = this.id || "";
            var match = id.match(regex) || [];
            if (match.length == 3) {
                this.id = match[1] + (cloneIndex);
            }
    });
    cloneIndex++;
});

Есть только одна глупая часть :) .attr("id", "clonedInput" + $(".clonedInput").length) но она работает;)

JAvascript - JQuery недавний (с поддержкой .on ())

var regex = /^(.+?)(\d+)$/i;
var cloneIndex = $(".clonedInput").length;

function clone(){
    $(this).parents(".clonedInput").clone()
        .appendTo("body")
        .attr("id", "clonedInput" +  cloneIndex)
        .find("*")
        .each(function() {
            var id = this.id || "";
            var match = id.match(regex) || [];
            if (match.length == 3) {
                this.id = match[1] + (cloneIndex);
            }
        })
        .on('click', 'button.clone', clone)
        .on('click', 'button.remove', remove);
    cloneIndex++;
}
function remove(){
    $(this).parents(".clonedInput").remove();
}
$("button.clone").on("click", clone);

$("button.remove").on("click", remove);

рабочий пример здесь

4 голосов
/ 27 декабря 2012

Другой вариант - использовать рекурсивную функцию:

// Accepts an element and a function
function childRecursive(element, func){
    // Applies that function to the given element.
    func(element);
    var children = element.children();
    if (children.length > 0) {
        children.each(function (){
            // Applies that function to all children recursively
            childRecursive($(this), func);
        });
    }
}

Затем вы можете создать одну или три функции для установки атрибутов и значений полей формы, которые еще не были клонированы:

// Expects format to be xxx-#[-xxxx] (e.g. item-1 or item-1-name)
function getNewAttr(str, newNum){
    // Split on -
    var arr = str.split('-');
    // Change the 1 to wherever the incremented value is in your id
    arr[1] = newNum;
    // Smash it back together and return
    return arr.join('-');
}

// Written with Twitter Bootstrap form field structure in mind
// Checks for id, name, and for attributes.
function setCloneAttr(element, value){
    // Check to see if the element has an id attribute
    if (element.attr('id') !== undefined){
        // If so, increment it
        element.attr('id', getNewAttr(element.attr('id'),value));
    } else { /*If for some reason you want to handle an else, here you go*/ }
    // Do the same with name...
    if(element.attr('name') !== undefined){
        element.attr('name', getNewAttr(element.attr('name'),value));
    } else {}
    // And don't forget to show some love to your labels.
    if (element.attr('for') !== undefined){
        element.attr('for', getNewAttr(element.attr('for'),value));
    } else {}
}

// Sets an element's value to ''
function clearCloneValues(element){
    if (element.attr('value') !== undefined){
        element.val('');
    }
}

Затем добавьте некоторую разметку:

<div id="items">
    <input type="hidden" id="itemCounter" name="itemCounter" value="0">
    <div class="item">
        <div class="control-group">
            <label class="control-label" for="item-0-name">Item Name</label>
            <div class="controls">
                <input type="text" name="item-0-name" id="item-0-name" class="input-large">
            </div>
        </div><!-- .control-group-->
        <div class="control-group">
            <label for="item-0-description" class="control-label">Item Description</label>
            <div class="controls">
                <input type="text" name="item-0-description" id="item-0-description" class="input-large">
            </div>
        </div><!-- .control-group-->
    </div><!-- .item -->
</div><!-- #items -->

<input type="button" value="Add Item" id="addItem">

И тогда все, что вам нужно, это немного jQuery, чтобы собрать все это вместе:

$(document).ready(function(){
    $('#addItem').click(function(){
        //increment the value of our counter
        $('#itemCounter').val(Number($('#allergyCounter').val()) + 1);
        //clone the first .item element
        var newItem = $('div.item').first().clone();
        //recursively set our id, name, and for attributes properly
        childRecursive(newItem, 
            // Remember, the recursive function expects to be able to pass in
            // one parameter, the element.
            function(e){
                setCloneAttr(e, $('#itemCounter').val());
        });
        // Clear the values recursively
        childRecursive(newItem, 
            function(e){
                clearCloneValues(e);
            }
        );
        // Finally, add the new div.item to the end
        newItem.appendTo($('#items'));
    });
});

Очевидно, вы неОбязательно нужно использовать рекурсию, чтобы получить все, если вы точно знаете, что нужно клонировать и изменить.Однако эти функции позволяют вам повторно использовать их для любого размера вложенной структуры с любым количеством полей, сколько вам нужно, при условии, что все они названы с правильным шаблоном.

Здесь есть работающий jsFiddle здесь .

4 голосов
/ 05 ноября 2011

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

Хорошо, вот быстрый код здесь .

В основном эта часть является наиболее важной:

(parseInt(/test(\d+)/.exec($(this).attr('id'))[1], 10)+1

Он анализирует текущий идентификатор (используя RegEx, чтобы убрать число из строки) и увеличивает его на 1. В вашем случае вместо «test» следует поставить «clonedInput», а также не только увеличить значение основного идентификатор элемента, но также три изнутри (категория, подкатегория и подкатегория). Это должно быть легко, если у вас есть новый идентификатор.

Надеюсь, это поможет. :)

0 голосов
/ 15 марта 2017

Добавьте атрибут данных к входу для получения имени поля, увеличьте значение переменной.

html:

<td>
   <input type="text" data-origin="field" name="field" id="field" required="" >
  <div role="button" onclick='InsertFormRow($(this).closest("tr"),"tableID","formID");' id="addrow"> + </div>

</td>

и поместите эту функцию JavaScript

varrowNum = 1;

var InsertFormRow = function(row, ptable, form)
{
    nextrow = $(row).clone(true).insertAfter(row).prev('#' + ptable + ' tbody>tr:last');
    nextrow.attr("id", rowNum);
    nextrow.find("input").each(function() {
        this.name =  $(this).data("origin") + "_" + rowNum;
        this.id =  $(this).data("origin") + "_" + rowNum;
    });
    rowNum++;     
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...