2

I have a html with three inputs like:

enter image description here

Html:

<div class="form-group" id="item-list0">
    <label>Role Name</label>
    <input asp-for="RoleClaimList[0].Role.Name" class="form-control roles" />
    <div id="claim-list0">
        <label>Claim Type</label>
        <input asp-for="RoleClaimList[0].ClaimList[0].Type" class="form-control claimType" />
        <label>Claim Value</label>
        <input asp-for="RoleClaimList[0].ClaimList[0].Value" class="form-control claimValue" />
    </div>
    <a href="#" id="addClaim">Add another claim</a>
</div>

<a href="#" id="add">Add another role</a>

As you can see I have two actions "Add another role" and "Add another claim"

If I press add another claim it just replicate Claim Type and Claim Value inputs

If I press "Add another role" it add all inputs again

I achieve that with Jquery as:

<script>
    $(function () {
        var roleIndex = 0;
        var claimIndex = 0;
        $("#add").click(function (e) {
            e.preventDefault();
            roleIndex = roleIndex + 1;
            claimIndex = 0;
            var n = '<div id="item-list' + roleIndex +'"><label>Role Name</label><input class="form-control" name="RoleClaimList[' + roleIndex + '].Role.Name" /></div>'
            var m = '<div id="claim-list' + roleIndex+'"><label>Claim Type</label><input class="form-control"  name="RoleClaimList[' + roleIndex + '].ClaimList[' + claimIndex + '].Type" />'
            var c = '<label>Claim Value</label><input class="form-control"  name="RoleClaimList[' + roleIndex + '].ClaimList[' + claimIndex + '].Value" />  </div>'
            $("#item-list" + (roleIndex - 1) + "").append(n);
            $("#claim-list" + (roleIndex - 1) + "").append(m);
            $("#claim-list" + (roleIndex - 1) + "").append(c);
        });

        $("#addClaim").click(function (e) {
            e.preventDefault();
            claimIndex = claimIndex + 1;
            var m = '<div id="claim-list' + claimIndex + '"><label>Claim Type</label><input class="form-control"  name="RoleClaimList[' + roleIndex + '].ClaimList[' + claimIndex + '].Type" />'
            var c = '<label>Claim Value</label><input class="form-control"  name="RoleClaimList[' + roleIndex + '].ClaimList[' + claimIndex + '].Value" />  </div>'
            $("#claim-list" + (claimIndex - 1) + "").append(m);
            $("#claim-list" + (claimIndex - 1) + "").append(c);
        });

    });
</script>

If I add claim it works correctly. Problem start when I add a new role. It should replicate first tree inputs in same order of first one, but it is creating Claim Type first then Claim Value and finally Role Name as this picture:

enter image description here

What I'm doing wrong there? Regards

Jonathan
  • 601
  • 9
  • 26
  • Consider how your logic is using both `roleIndex` and `claimIndex` to determine which `#claim-list` to append to. You're going to be duplicating claim-list ids – Taplar Nov 12 '18 at 23:33

1 Answers1

0

What's wrong is that you are appending your new #item-list1 div into the existing #item-list0, making it a nested structure.

Same goes to your #claim-list, it became a nested structure:

#item-list0
⤷ #claim-list0
  ⤷ #claim-list1
  ⤷ #claim-list2
  ⤷ #claim-list3
⤷ #item-list1
⤷ #item-list2
⤷ #item-list3

What you should do instead is to append them outside:

  1. Append new #item-listx to <body></body> or whatever parent element.
  2. Append new #claim-list to its corresponding #item-lists.

So it would be your intended structure:

#item-list0
⤷ #claim-list0
⤷ #claim-list1
⤷ #claim-list2

#item-list1
⤷ #claim-list0
⤷ #claim-list1
⤷ #claim-list2

And if you look at it, there comes a few more problems with your code:

  1. You will have duplicated id.
  2. claimIndex will not work properly because you reset it every time #add is clicked (what happens if I click "addClaim" to previous roles after I add new role?)

Below is a sample code that works properly (I think, may not actually be your use case). I have restructured it so that it can be easily understood without much explanation. Please edit as needed to suit your actual code base:

var roleIndex = 0;

$('#add')
  .on('click', addRole) // Add onclick handler
  .trigger('click');    // Trigger it on execution to create the first set

function addRole(){
  roleIndex += 1;

  // Set `claimIndex` here, not outside of the scope
  // because you need it in each separate added role
  // so that the claimIndex of each role can correctly counts independently
  var claimIndex = 0,
      roleClaimList = 'RoleClaimList[' + roleIndex + ']';

  var $itemList = $('<div></div>')
    .addClass('form-group')
    .attr('id', 'item-list-' + roleIndex);

  var $roleLabel = $('<label></label>')
    .text('Role Name')
    .appendTo($itemList);

  var $roleInput = $('<input>')
    .addClass('form-control roles')
    .attr('asp-for', roleClaimList + '.Role.Name')
    .appendTo($itemList);

  var $addClaimButton = $('<a></a>')
    .text('Add another claim')
    .attr('href', '#')
    .addClass('addClaim')
    .on('click', addClaim)
    .appendTo($itemList);

  $addClaimButton.trigger('click');

  $itemList.insertBefore(this);

  // Create this function here, not outside
  // because it needs the `claimIndex` in scope
  function addClaim(e){
    e.preventDefault();
    claimIndex += 1;

    var $claimGroup = $('<div></div>')
      .attr('id', 'claim-list-' + roleIndex + '-' + claimIndex)
      .insertBefore($addClaimButton);

    var $typeLabel = $('<label></label')
      .text('Claim Type')
      .appendTo($claimGroup);

    var $typeInput = $('<input>')
      .addClass('form-control claimType')
      .attr('asp-for', roleClaimList + '.ClaimList[' + claimIndex + '].Type')
      .appendTo($claimGroup);

    var $valueLabel = $('<label></label')
      .text('Claim Value')
      .appendTo($claimGroup);

    var $valueInput = $('<input>')
      .addClass('form-control claimValue')
      .attr('asp-for', roleClaimList + '.ClaimList[' + claimIndex + '].Value')
      .appendTo($claimGroup);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="form-group" id="item-list-0"></div>
<a href="#" id="add">Add another role</a>

To know more about scoping, read this amazing answer.

yqlim
  • 6,898
  • 3
  • 19
  • 43