2010-04-16 13 views
16

Estoy buscando una manera efectiva de clonar/cambiar el nombre o volver a crear campos de dirección para ofrecer la capacidad de enviar varias direcciones en la misma página. Así, con forma de ejemplo como este:Clonación y cambio de nombre de elementos de formulario con jQuery

<div id="addresses"> 
    <div class="address"> 
    <input type="text" name="address[0].street"> 
    <input type="text" name="address[0].city"> 
    <input type="text" name="address[0].zip"> 
    <input type="text" name="address[0].state"> 
    </div> 
</div> 
<a href="" id="add_address">Add address form</a> 

De lo que puedo entender que hay dos opciones para hacerlo:

  1. recrear el campo de formulario por el campo y el incremento del índice que es un poco prolijo:

    var index = $(".address").length; 
    
    $('<`input`>').attr({ 
    name: 'address[' + index + '].street', 
    type: 'text' 
    }).appendTo(...); 
    
    $('<`input`>').attr({ 
    name: 'address[' + index + '].city', 
    type: 'text' 
    }).appendTo(...); 
    
    $('<`input`>').attr({ 
    name: 'address[' + index + '].zip', 
    type: 'text' 
    }).appendTo(...); 
    
    $('<`input`>').attr({ 
    name: 'address[' + index + '].state', 
    type: 'text' 
    }).appendTo(...); 
    
  2. capa existente de clonar y reemplazar el nombre en el clon:

    $("div.address").clone().appendTo($("#addresses")); 
    

¿Cuál te recomienda usar en términos de ser más eficiente y si su # 2 ¿podría sugerir cómo iba a ir sobre la búsqueda y la sustitución de todas las apariciones de [0] por [1] ([n]) Gracias.

Respuesta

29

En teoría, la forma más sencilla sería la de clonar a continuación, cambiar el nombre:

var newaddress= $("#addresses div.address").eq(0).clone(); 
newaddress.find('input').each(function() { 
    this.name= this.name.replace('[0]', '['+i+']'); 
}); 
$('#addresses').append(newaddress); 

Sin embargo:

a. jQuery's clone() es una obra realmente desagradable. En IE, serializa los nodos a HTML, procesa la cadena HTML con regex (!) Para eliminar sus atributos internos de ID del job-job y luego le pide al navegador que vuelva a analizarlo. Esta es una de mis partes menos favoritas de jQuery: es altamente propensa a errores, pierde algo de información y es lenta (no es que la velocidad sea importante para el trabajo bastante pequeño que parece que está haciendo aquí).

El método cloneNode(true) nativo del navegador es mucho mejor, pero no se puede usar realmente si se está haciendo algo de jQuery porque copiará los ID internos de jQuery, lo que podría confundir su secuencia de comandos. Ugh. Que desastre.

b. Cuando cambia el nombre de una entrada, ya sea por input.name como aquí o por attr() como en su ejemplo, existen problemas en IE < = 7.

En particular, aunque enviará las entradas con el nombre de control correcto, no se indexarán con el nombre correcto en form.elements HTMLCollection (o en form, aunque no debería usar eso de todos modos). Esto no es necesariamente un problema si está seleccionando entradas basadas en identificadores o selectores jQuery en lugar de la interfaz HTMLCollection de la vieja escuela. Lo que es peor es que los botones de opción, si los usa, no estarán agrupados por nombre.

Si esto es una preocupación para ti, me temo que usar innerHTML/html() para crear el div, como en la respuesta de pst, es tu única opción. (Siempre se puede combinar los dos, creando usando HTML, entonces el cambio de los otros atributos y contenido del texto usando text(), attr(), val() etc., para evitar los problemas habituales de HTML-escape cuando vas por ahí pegando cadenas de texto en HTML.)

+0

¡Eso es perfecto! gracias por la explicación del funcionamiento interno del clon así como un recordatorio sobre problemas con el cambio de nombre de la entrada en IE. – Micor

4

Es mucho menos detallado si lo escribe con cordura :-) Probablemente solo use clone y lo agregue. Sin embargo,, obtendrá nombres duplicados. Esto no es un gran problema si su back-end puede manejar correctamente "address []. Street", pero puede que no y en tal caso necesitaría limpiar después del clon. Por lo tanto, recomendaría "esconderlo en una función de construcción ordenada".

function createAddress (index) { 
    return jQuery(replace('\ 
    <div class="address">\ 
     <input type="text" name="address[{i}].street">\ 
     <input type="text" name="address[{i}].city">\ 
     <input type="text" name="address[{i}].zip">\ 
     <input type="text" name="address[{i}].state">\ 
    </div>\ 
    ', {i: index})) 
} 

Where replace es una función ordenada que comprende un mapeo de interpolación simple. Prefiero "mantener el marcado en algo que se parece al marcado".

Preocuparse por el rendimiento aquí probablemente no esté justificado.

+0

Esa es sin duda una forma más sensata de hacerlo :) La razón por la que me inclino por el método de clonación porque el estado es en realidad un campo seleccionado poblado con una lista de estados, por lo que la clonación parece ser más fácil. ¿Podría usarlo aquí de una manera similar y obtener html() de mi div clonado y luego reemplazar el índice usando regex? – Micor

0

me creer que estoy pasando lo mismo y encontré algunos gran fuente que dice así:

<script type="text/javascript"> 
    function trimNums(stringToTrim) 
    { 
     return stringToTrim.replace(/\d+$/,""); 
    } 
    function dupForm(divId, divClass, btnAdd, btnRm) 
    { 
    //alert(divId+' '+divClass); 
     var num  = $(divClass).length; 
     var newNum = new Number(num + 1); 
     var i; 
     var newElem = $('#' + divId + num).clone().attr('id', divId + newNum).fadeIn('slow'); 
     for (i=0; i < newElem.children().length; i++) 
     { 
      var attrId = trimNums(newElem.children(':eq('+i+')').attr('id')); 
      var attrName = trimNums(newElem.children(':eq('+i+')').attr('name')); 
      newElem.children(':eq('+i+')').attr('id', attrId + newNum).val(''); 
     } 
     $('#' + divId + num).after(newElem); 
     $('#' + btnRm).attr('disabled',''); 
     if (newNum == 15) 
      $('#' + btnAdd).attr('disabled','disabled'); 
    } 
    function rmForm(divId, divClass, btnAdd, btnRm) 
    { 
     var num = $(divClass).length; 
     $('#' + divId + num).remove(); 
     $('#' + btnAdd).attr('disabled',''); 
     if (num-1 == 1) 
      $('#' + btnRm).attr('disabled','disabled'); 
    } 
</script> 

y el código hTML es:

<form id="myForm" action="testingForm.php" method="post"> 
<div id="input1" style="margin-bottom:4px;" class="clonedInput"> 
    Part #: <input name="part[]" type="text" id="part1" size="10" maxlength="15" /> 
    Description: <input name="description[]" type="text" id="description1" size="30" maxlength="50" /> 
    Qty: <input name="quantity[]" type="text" id="quantity1" size="5" maxlength="5" /> 

....

Cuestiones relacionadas