14

I have a form which asks users for their personal info and their family members.
fields of the family members section is repeating.
my question is what is best practice to handle these kind of repeating forms?
I currently use AJAX to repeat forms but how to collect data from these repeating fields? enter image description here


since some one asked for how I repeat form, I do it like this: AJAX Call

$(document).on('click', '.btn-add-item', function (e) {
    e.preventDefault();
    var $results = $('#results');
    $.ajax({
        url: '/AJAX/AddFamilyForm',
        type: 'post',
        success: function (data) {
            $(data).appendTo($results);
            afterAJAX();
        }
    });
});

C# code

[HttpPost]
public PartialViewResult AddFamilyForm()
{
    if (!Request.IsAjaxRequest()) return null;
    return PartialView("_FamilyForm");
}
4
  • Could you share your code how to repeat form fields? I searched this exact problem, but found no solution Commented Aug 13, 2014 at 12:56
  • How you handle that, with javascript or you make post back on each new creation? If you use javascript, do you use jQuery ? Commented Aug 13, 2014 at 13:04
  • 1
    Check out this post from Phil Haack. Commented Aug 13, 2014 at 13:06
  • Most of the answers are close, but they all make assumptions on many things. It would help a lot if you would post your model and, most important, your views (main and addfamilyform). Commented Aug 13, 2014 at 13:23

3 Answers 3

20

This is some skeleton code on how to get this to work with proper model-binding in MVC. You'll need to write some JS to be able to delete/add new rows.

Model

public class MyModel
{
    public FamilyMembers[] FamilyMembers { get; set; }
}

View

<button id="addNewFamilyMember" type="button">Add</button>
@if (Model.FamilyMembers != null)
{
    for (int i = 0; i < Model.FamilyMembers.Length; i++)
    {
        <tr>
            <td>
                <button type="button">Delete</button>
                @Html.Hidden("FamilyMembers.Index", i)
            </td>
            <td>
                @Html.TextBoxFor(m => Model.FamilyMembers[i].Relation)
            </td>
            <td>
                @Html.TextBoxFor(m => Model.FamilyMembers[i].FullName)
            </td>
        </tr>
    }
}

Below is the code for adding a new member. It creates html dynamically and is able to bind to the posted model because of naming conventions. time gives each added row a unique id so all the data stays together.

JS (using Jquery)

var hidden = '@Html.Hidden("FamilyMembers.Index", "{id}")';
var relationHtml = '@Html.TextBox("FamilyMembers[{id}].Relation")';
var fullNameHtml = '@Html.TextBox("FamilyMembers[{id}].FullName")';

$("#addNewFamilyMember").on("click", function () {
        var time = Date.now();

        var deleteHtml = "<button type='button'>Delete</button>";

        $("#familyMembers-table").find("tbody")
         .append($("<tr><td>" + hidden.replace("{id}", time) + deleteHtml + "</td>" +
            "<td>" + relationHtml.replace("{id}", time) + "</td>" +
            "<td>" + fullNameHtml.replace("{id}", time) + "</td></tr>"));
});
Sign up to request clarification or add additional context in comments.

3 Comments

This is the closest answer to the solution. I think it would help greatly if you could provide some details for the "template" used to add a new family member.
I used to work on web forms. Still for complicated stuff on MVC, we have to do some dodge things to get around. Also thank you for the solution
This is brilliant! Best solution around IMO
1

One of the solution could be combination of hidden field and control name.

Steps:

  1. Use a hidden field to keep the count the number of row.
  2. Create controls with name like text_relation_1 for first row and text_relation_2 for second row and so on
  3. Generate other controls in same way.
  4. Increase and decrease the hidden field value so that when values post you can know the number of rows added by the user

On your action use FormCollection and loop though hidden field number and get the values from FormCollection

Like suppose I created 3 rows then I can create a action like below

public ActionResult SomeActionMethod(FormCollection formCollection, string hid)
{
    for(int i=1;i<hid;i++)
    {
        var relationId="text_relation_"+i;
        var firstrealtion=formCollection[relationId];
        ...
    }
}

Comments

0

You don't need any extra Ajax requests for this, since you can use established and standard <form> features.

Just append [] to the name of the added forms and you'll end up with an array rather than a single value in your HTTP request once the form is submitted:

<input type="text" name="relation[]" /><input type="text" name="fullname[]" />
<input type="text" name="relation[]" /><input type="text" name="fullname[]" />
<input type="text" name="relation[]" /><input type="text" name="fullname[]" />

In this example you'd end up with an array relation and an array fullname, both containing your datasets.

4 Comments

Except that you wont know with relation matches up to which fullname.
Are you sure about that? I'd expect them to get filled in the same order they appear in. But even then, you could just add the actual index rather than empty brackets.
They do get added to the POST in the order in which they appear in. However I think it's dangerous to rely on that mechanism considering the model binder doesn't guarantee this ordering.
Ah okay, that's an important note then, since I've only used that with static HTML and PHP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.