Clone element by changing name value

Asked

Viewed 93 times

1

Example scenario

I have a form which it possesses in the name, 2 specific values: X[Y]

X is a reference to the vision code, and Y concerning the field of my vision, and the value of input, shall be the value for XY.

Could it be considered a matrix!? Anyway...

The example is below:

function clone($e) {
  $c = $($e).parents("tr");
  $($c).clone().appendTo("#clones");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form id="FormABC" onsubmit="return false">

  <table>
    <thead>
      <tr>
        <th>Fixo 1</th>
        <th>Fixo 2</th>
        <th>Fixo 3</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><input type="date" name="fx[a]" value="2020-01-01"></td>
        <td><input type="text" name="fx[b]" value="teste"></td>
        <td><input type="number" name="fx[c]" value="123"></td>
      </tr>
    </tbody>
  </table>

  <br><br>

  <table>
    <thead>
      <tr>
        <th></th>
        <th class="table-secondary">Campo 1</th>
        <th class="table-secondary">Campo 2</th>
        <th class="table-secondary">Campo 3</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th class="table-secondary"><button onclick="clone(this)">Visão 1</button></th>
        <td><input type="number" name="1[1]" value="1"></td>
        <td><input type="number" name="1[2]" value="2"></td>
        <td><input type="number" name="1[3]" value="3"></td>
      </tr>
      <tr>
        <th class="table-secondary"><button onclick="clone(this)">Visão 2</button></th>
        <td><input type="number" name="2[1]" value="4"></td>
        <td><input type="number" name="2[2]" value="5"></td>
        <td><input type="number" name="2[3]" value="6"></td>
      </tr>
    </tbody>
  </table>

</form>

<br><br>

<div id="clones"><p>Clones</p></div>


The problem

Above, when I make a "clone", it will bring me a copy, but when I use the serialize(), it will override the values for sending, and so will only the last values according to sequence html.

Example: If I clone vision 2 and replace the values for 7, 8 and 9, my return will be:

Array
(
    [fx] => Array
        (
            [a] => 2020-01-01
            [b] => teste
            [c] => 123
        )

    [1] => Array
        (
            [1] => 1
            [2] => 2
            [3] => 3
        )

    [2] => Array
        (
            [1] => 7
            [2] => 8
            [3] => 9
        )

)

Example of the possible solution

What I thought, would add an "accountant" at the beginning of name.

For example:

ANTES:

<tr>
    <th class="table-secondary"><button onclick="clone(this)">Visão 1</button></th>
    <td><input type="number" name="1[1]" value="1"></td>
    <td><input type="number" name="1[2]" value="2"></td>
    <td><input type="number" name="1[3]" value="3"></td>
</tr>

DEPOIS:

<tr>
    <th class="table-secondary"><button onclick="clone(this)">Visão 1</button></th>
    <td><input type="number" name="1[1][1]" value="1"></td>
    <td><input type="number" name="2[1][2]" value="2"></td>
    <td><input type="number" name="3[1][3]" value="3"></td>
</tr>

That way, I would have each individual value, keeping my X and Y, adding the "counter" in front C[X][Y].

Exit:

Array
(
    [fx] => Array
        (
            [a] => 2020-01-01
            [b] => teste
            [c] => 123
        )

    [1] => Array
        (
            [1] => Array
                (
                    [1] => 1
                )

        )

    [2] => Array
        (
            [1] => Array
                (
                    [2] => 2
                )

        )

    [3] => Array
        (
            [1] => Array
                (
                    [3] => 3
                )

        )

    [4] => Array
        (
            [2] => Array
                (
                    [1] => 4
                )

        )

    [5] => Array
        (
            [2] => Array
                (
                    [2] => 5
                )

        )

    [6] => Array
        (
            [2] => Array
                (
                    [3] => 6
                )

        )

    [7] => Array
        (
            [2] => Array
                (
                    [1] => 7
                )

        )

    [8] => Array
        (
            [2] => Array
                (
                    [2] => 8
                )

        )

    [9] => Array
        (
            [2] => Array
                (
                    [3] => 9
                )

        )

)

The difficulty would be to catch this name, treat one by one not to define a value already used in another element, and thus override that value.


Doubt

  • I wonder how I could solve this problem?
  • Do you want to serialize inputs out of the form? Serialize only works with form.

  • No, everything inside. In the code is inside the form... sorry... kkk

  • I thought of a way, using the id, but it is a braba gambiarra... I prefer to see other more correct alternatives...

  • Then @Rbz. Take a look at the answer and tell me what you found. Dude, I spent almost 2 hours on this between understanding what you wanted and coming up with a solution. But I think it looks good. I hope it works out for you. =]

1 answer

1


One solution is to create array patterns by separating them by the view codes. For example, let’s say I cloned the fields this way:

inserir a descrição da imagem aqui

The result will be:

Array
(
    [fx] => Array
        (
            [a] => 2020-01-01
            [b] => teste
            [c] => 123
        )

    [1] => Array
        (
            [0] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                )

            [1] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                )

        )

    [2] => Array
        (
            [0] => Array
                (
                    [0] => 4
                    [1] => 5
                    [2] => 6
                )

            [1] => Array
                (
                    [0] => 4
                    [1] => 5
                    [2] => 6
                )
        )
)

Note that the main array contains 2 indexes ([1] and [2]) where in each one they are grouped in indexes (starting from the 0) the lines relating to each vision.

To achieve this, the standard of the Names must be:

<tr>
  <th class="table-secondary"><button onclick="clone(this)">Visão 1</button></th>
  <td><input type="number" name="1[0][]" value="1"></td>
  <td><input type="number" name="1[0][]" value="2"></td>
  <td><input type="number" name="1[0][]" value="3"></td>
</tr>
<tr>
  <th class="table-secondary"><button onclick="clone(this)">Visão 2</button></th>
  <td><input type="number" name="2[0][]" value="4"></td>
  <td><input type="number" name="2[0][]" value="5"></td>
  <td><input type="number" name="2[0][]" value="6"></td>
</tr>

Lines that already appear on the page should start with index [0]. For example, when cloning the "Vision 1" line, the clone will be:

<tr>
  <th class="table-secondary"><button onclick="clone(this)">Visão 1</button></th>
  <td><input type="number" name="1[1][]" value="1"></td>
  <td><input type="number" name="1[1][]" value="2"></td>
  <td><input type="number" name="1[1][]" value="3"></td>
</tr>

See that was creating a new index [1]. Re-clone the same line, you’ll go to [2] and so on.

A remark:

As you are cloning table rows, they should be inserted into a table. So the div #clones should have a table empty to receive lines:

<div id="clones">
   <p>Clones</p>
   <table></table>
</div>

You can even put the id="clones" straight on the table, but I left as is.

The code that will make all this control and changes in the Names is as follows (see explanatory comments):

function clone($e) {

   $c = $($e).parents("tr");
   var v = $("input:eq(0)", $c).attr("name")[0]; // código da visão (1 ou 2)

   var ultimo = $("#clones [name^='"+v+"[']:last"); // pega o último input da visão clonada
   var idx = !ultimo.length ? 1 : +$(ultimo)[0].name.match(/\[(.+?)\]/)[1]+1; // pega o último índice clonado
   var klone = $($c).clone(); // elemento clonado

   $("input", klone).attr("name", v+"["+idx+"][]"); // altera os names de cada input do clone

   klone.appendTo("#clones table"); // faz o append
}

It basically changes the clone (inputs Names) before making the append.

  • Boy, did you know that business was a little complex, but not that complex! rs... But about your answer, I can’t have 0 in the array... I need you to always have an X array that has a key Y receiving the value of the field. As for the clone not being inside the table, it was my fault, because it needs to be, is part of the form to be added below. But I think with your answer, I might be able to solve it. I’ll try, probably take a while, because I have many visions x fields ! Thank you for now!

  • Is that the [0] is the first line, the [1] the second and so consecutively. It is always better to treat arrays based 0 when they are collections of the same group. The way I did there seemed the best option because you can easily treat it in the backend.

  • I get it... is that these 2 items X and Y, are id FK’s, where I do the insert (x, y, value)... when I made the form, there would be no duplicates, but now you will need, that’s where the problem came from! kk Anyway, I’m already going to give +1 because at the very least it will help me in something all this.

  • It has a detail... it would have to take the largest number of the "counter" of all elements of the form, to have no overlap problem.

  • I did it in the code and I disappeared +1, here: +$(ultimo)[0].name.match(/\[(.+?)\]/)[1]+1

  • So I got it wrong here // pega o último índice clonado...

  • He gets the [n] and sum the n +1.

  • Yes, it is that you did fixed, I will do the external counter, to stay C[X][Y]. But then I need to clone, and go 1 to 1..

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.