Tengo un formulario donde se pueden agregar filas al hacer clic en un botón. También se pueden eliminar con un clic.
Mi html en la carga de la página se ve así:
<div class="invoicerow"> <div class="row"> <div class="col-12 col-md-2"> <label for="">Aantal</label> <div class="inputstyle mb-10"> <input type="text" name="invoice_row[][invoice_quantity]"> </div> </div> <div class="col-12 col-md-5"> <label for="">Titel</label> <div class="inputstyle mb-10"> <input type="text" name="invoice_row[][invoice_title]"> </div> </div> <div class="col-12 col-md-2"> <label for="">Prijs</label> <div class="inputstyle mb-10"> <input type="text" name="invoice_row[][invoice_price]"> </div> </div> <div class="col-12 col-md-2"> <label for="">Totaal</label> <div>€99,05</div> </div> <div class="col-12 col-md-1 d-flex align-center"> <i class="fas fa-trash-alt delete_invoice_row"></i> </div> <div class="col-12"> <label for="">Beschrijving</label> <div class="inputstyle mb-10"> <textarea type="text" name="invoice_row[][invoice_desc]"></textarea> </div> </div> </div> </div> Quiero agrupar todos los resultados cuando hay varios elementos de invoicerow de facturas presentes.
Ahora, cuando publico, la matriz publicada se ve así:
Array ( [other_info] => [invoice_row] => Array ( [0] => Array ( [invoice_quantity] => ) [1] => Array ( [invoice_title] => ) [2] => Array ( [invoice_price] => ) [3] => Array ( [invoice_desc] => ) [4] => Array ( [invoice_quantity] => ) [5] => Array ( [invoice_title] => ) [6] => Array ( [invoice_price] => ) [7] => Array ( [invoice_desc] => ) ) )Si bien esto es lo que estoy buscando:
Array ( [other_info] => [invoice_row] => Array ( [0] => Array ( [invoice_quantity] => [invoice_title] => [invoice_price] => [invoice_desc] => ) [1] => Array ( [invoice_quantity] => [invoice_title] => [invoice_price] => [invoice_desc] => ) ) ) Sé que puedo cambiar esta invoice_row[][invoice_price] a invoice_row[0][invoice_price] por ejemplo para agruparlos, pero esto no funcionará ya que mis campos de entrada se pueden agregar y eliminar dinámicamente.
¿Cuál es la mejor solución para esto?
Este es mi código que agrega y elimina los campos de entrada:
$(".add_invoice_row").click(function () { var invoicehtml = '' + '<div class="invoicerow">' + ' <div class="row">' + ' <div class="col-12 col-md-2">' + ' <label for="">Aantal</label>' + ' <div class="inputstyle mb-10">' + ' <input type="text" name="invoice_row[][invoice_quantity]">' + ' </div>' + ' </div>' + ' <div class="col-12 col-md-5">' + ' <label for="">Titel</label>' + ' <div class="inputstyle mb-10">' + ' <input type="text" name="invoice_row[][invoice_title]">' + ' </div>' + ' </div>' + ' <div class="col-12 col-md-2">' + ' <label for="">Prijs</label>' + ' <div class="inputstyle mb-10">' + ' <input type="text" name="invoice_row[][invoice_price]">' + ' </div>' + ' </div>' + ' <div class="col-12 col-md-2">' + ' <label for="">Totaal</label>' + ' <div>€99,05</div>' + ' </div>' + ' <div class="col-12 col-md-1 d-flex align-center">' + ' <i class="fas fa-trash-alt delete_invoice_row"></i>' + ' </div>' + ' <div class="col-12">' + ' <label for="">Beschrijving</label>' + ' <div class="inputstyle mb-10">' + ' <textarea type="text" name="invoice_row[][invoice_desc]"></textarea>' + ' </div>' + ' </div>' + ' </div>' + '</div>' + ''; $('.new_invoice_row').append(invoicehtml); create_invoice_form = $(".create_invoice_form").serialize(); $.ajax({ type:'post', url:"invoice_custom.php", data:({ create_invoice_form: create_invoice_form }), success:function(data){ console.log(data); } }); }); $(document).on('click', '.delete_invoice_row', function () { $(this).closest('.invoicerow').remove(); });Ejemplo jsFiddle: https://jsfiddle.net/xbLyp9f2/1/
Puede usar jquery.serializeJSON , un pequeño complemento de jquery, para obtener resultados en un formato JSON agradable. El JSON se puede analizar fácilmente en el lado del servidor.
$(".add_invoice_row").click(function() { var invoicehtml = '' + '<div class="invoicerow">' + ' <div class="row">' + ' <div class="col-12 col-md-2">' + ' <label for="">Aantal</label>' + ' <div class="inputstyle mb-10">' + ' <input type="text" name="invoice[row][][invoice_quantity]">' + ' </div>' + ' </div>' + ' <div class="col-12 col-md-5">' + ' <label for="">Titel</label>' + ' <div class="inputstyle mb-10">' + ' <input type="text" name="invoice[row][][invoice_title]">' + ' </div>' + ' </div>' + ' <div class="col-12 col-md-2">' + ' <label for="">Prijs</label>' + ' <div class="inputstyle mb-10">' + ' <input type="text" name="invoice[row][][invoice_price]">' + ' </div>' + ' </div>' + ' <div class="col-12 col-md-2">' + ' <label for="">Totaal</label>' + ' <div>€99,05</div>' + ' </div>' + ' <div class="col-12 col-md-1 d-flex align-center">' + ' <i class="fas fa-trash-alt delete_invoice_row"></i>' + ' </div>' + ' <div class="col-12">' + ' <label for="">Beschrijving</label>' + ' <div class="inputstyle mb-10">' + ' <textarea type="text" name="invoice[row][][invoice_desc]"></textarea>' + ' </div>' + ' </div>' + ' </div>' + '</div>' + ''; $('.new_invoice_row').append(invoicehtml); }); //create_invoice_form = $(".create_invoice_form").serialize(); /*$.ajax({ type: 'post', url: "invoice_custom.php", data: ({ create_invoice_form: create_invoice_form }), success: function(data) { console.log(data); } }); */ function onSubmit(form) { var data = $(form).serializeJSON(); console.log(data); console.log(JSON.stringify(data, undefined, 3)); return false; } $(document).on('click', '.delete_invoice_row', function() { $(this).closest('.invoicerow').remove(); }); <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.serializeJSON/3.2.1/jquery.serializejson.min.js"></script> <div class="col-12"> <p>See the console logs for output.</p> <form class="create_invoice_form" method="post" onsubmit='return onSubmit(this)'> <button type='submit'>Submit</button><br><hr> <div class="row"> <div class="col-12 col-md-6"> <label for="">Emailadres</label> <div class="inputstyle mb-10"> <input type="text" name="invoice[mail]" value='abc@gmail.com'> </div> </div> <div class="col-12 col-md-6"> <label for="">Datum</label> <div class="inputstyle mb-10"> <input type="date" name="invoice[date]"> </div> </div> <div class="col-12"> <div class="invoicerow"> <div class="row"> <div class="col-12 col-md-2"> <label for="">Aantal</label> <div class="inputstyle mb-10"> <input type="text" name="invoice[row][][invoice_quantity]" value='10'> </div> </div> <div class="col-12 col-md-5"> <label for="">Titel</label> <div class="inputstyle mb-10"> <input type="text" name="invoice[row][][invoice_title]" value='item 1'> </div> </div> <div class="col-12 col-md-2"> <label for="">Prijs ex. BTW</label> <div class="inputstyle mb-10"> <input type="text" name="invoice[row][][invoice_price]" value='btw'> </div> </div> <div class="col-12 col-md-2"> <label for="">Totaal</label> <div>€99,05</div> </div> <div class="col-12 col-md-1 d-flex align-center"> <i class="fas fa-trash-alt delete_invoice_row"></i> </div> <div class="col-12"> <label for="">Beschrijving</label> <div class="inputstyle mb-10"> <textarea type="text" name="invoice[row][][invoice_desc]">description</textarea> </div> </div> </div> </div> <div class="new_invoice_row"> </div> </div> </div> </form> </div> <div class="col-12"> <i class="fas fa-plus-square add_invoice_row"></i> </div> Tenga en cuenta cómo nombré las entradas de invoice[row][][invoice_quantity] .
Producción:
{ "invoice": { "mail": "abc@gmail.com", "date": "", "row": [ { "invoice_quantity": "10", "invoice_title": "item 1", "invoice_price": "btw", "invoice_desc": "description" }, { "invoice_quantity": "a", "invoice_title": "t", "invoice_price": "g", "invoice_desc": "sd" }, { "invoice_quantity": "3", "invoice_title": "3", "invoice_price": "3", "invoice_desc": "des3" } ] } } En php, puede convertir la cadena JSON de solicitud en un objeto usando $jObj = json_decode($jsonString);
Para que la solución dinámica (agregar los índices a los nombres de los formularios explícitamente) funcione de manera confiable, todo lo que necesita hacer es manejar la reindexación cuando elimina un elemento:
$(document).on('click', '.delete_invoice_row', function () { $(this).closest('.invoicerow').remove(); $('.invoicerow').each(function(idx, el) { $(el).find('[name^="invoice_row"]').each(function(iidx, iel) { $(iel).attr("name", iel.name.replace(/invoice_row\[\d+\]/, "invoice_row[" + idx + "]")); }); }); });Violín: https://jsfiddle.net/fg8rwexp/2/
En mi humilde opinión: no incruste HTML literal en su código JS a menos que sea realmente necesario. Oculte la plantilla HTML en una etiqueta de secuencia de comandos que contenga marcadores de texto de reemplazo (por ejemplo, para el índice).
Luego puede insertar un valor de índice real para cada fila agregada (generalmente agrego 1 al valor de fila más alto existente presente):
<script id="rowtemplate"> <div class="invoicerow"> <div class="row"> <div class="col-12 col-md-2"> <label for="">Aantal</label> <div class="inputstyle mb-10"> <input type="text" name="invoice_row[{row}][invoice_quantity]"> </div> </div> <div class="col-12 col-md-5"> <label for="">Titel</label> <div class="inputstyle mb-10"> <input type="text" name="invoice_row[{row}][invoice_title]"> </div> </div> <div class="col-12 col-md-2"> <label for="">Prijs</label> <div class="inputstyle mb-10"> <input type="text" name="invoice_row[{row}][invoice_price]"> </div> </div> <div class="col-12 col-md-2"> <label for="">Totaal</label> <div>{total}</div> </div> <div class="col-12 col-md-1 d-flex align-center"> <i class="fas fa-trash-alt delete_invoice_row"></i> </div> <div class="col-12"> <label for="">Beschrijving</label> <div class="inputstyle mb-10"> <textarea type="text" name="invoice_row[{row}][invoice_desc]"></textarea> </div> </div> </div> </div> </script> $('#rowtemplate').html() le dará la plantilla como una cadena.
https://jsfiddle.net/TrueBlueAussie/j41fzubp/2/
Dejé un comentario en el JSFiddle donde irían los reemplazos de cadenas, pero como ya ha aceptado otra respuesta, dejo que lo complete.