0

I'm trying to add an unspecified number of rows to my database. These rows are created dynamically by the user's request:

$(document).ready(function () {

    $(document).on('click', '#dataTable .add', function () {

        var row = $(this).closest('tr');

        if ($('#dataTable .add').length <= 100) {
            var clone = row.clone();

            // Clear the values.
            var tr = clone.closest('tr');
            tr.find('input[type=text]').val('');
            $(this).closest('tr').after(clone);
        } 
    });

    // Only delete row if there exists more than one.
    $(document).on('click', '#dataTable .removeRow', function () {
        if ($('#dataTable .add').length > 1) {
            $(this).closest('tr').remove();
        }
    });
});

So far what I am using to try and achieve this is a list with a maximum value of 100 elements (which I'd prefer a different method than this, perhaps one with no upper limit but this will do in the meantime), and I pass this list that I've created to my View():

// GET: Questions/Create
public ActionResult Create(int questionnaireUID)
{
    List<QUESTION> questions = new List<QUESTION>();
    for (var i = 0; i < 100; i++)
    {
        questions.Add(new QUESTION { QuestionnaireUID = questionnaireUID, Question1 = "" });
    }
    return View(questions);
}

In my View() here is the pertinent code sample that I am using to populate the values of my list (I believe my problems lie here...):

<table id="dataTable" name="dataTable">
@if (Model != null && Model.Count() > 0)
{
    <tr>
        @Html.HiddenFor(model => model[i].QuestionnaireUID)
        <td>
            @Html.EditorFor(model => model[i].Question1, new { htmlAttributes = new { @type = "text", @name = "question", @class = "question_input" } })
            @Html.ValidationMessageFor(model => model[i].Question1, "", new { @class = "text-danger" })
            <input type="button" name="addRow[]" class="add" value="Add">
            <input type="button" name="addRow[]" class="removeRow" value="Remove">
        </td>
    </tr>
    i++;
}
</table>

When I try to save this created list to my database, using the code below:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "QuestionnaireUID, Question1")] List<QUESTION> questions)
{
    if (ModelState.IsValid)
    {
        foreach (var question in questions)
        {
            db.QUESTIONS.Add(question);
        }
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(questions);
}

I am only able to save the first element of the list. The size of my list is always one, regardless of if the user dynamically generated 10 list elements.

Furthermore, if the first element has an error (e.g. it is empty) this error message is printed to all elements in the table. So, this being said although my list is able to generate in the view multiple elements/rows, for my database only one row is actually meaningful/used--which is the first row. How can I fix this?

Craig W.
  • 17,838
  • 6
  • 49
  • 82
  • Have you had a look at the payload (the HTTP POST request to the server)? – Charleh Apr 01 '15 at 14:17
  • Some options for dynamically adding and removing items shown [here](http://stackoverflow.com/questions/29161481/post-a-form-array-without-successful/29161796#29161796) and [here](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) –  Apr 01 '15 at 21:21

1 Answers1

0

As far as I know, MVC doesn't provide a built-in solution for handling dynamic/variable length lists. There are a few custom solutions that involve creating helpers to handle posting dynamic list objects. Here is one that I have used many times in the past, and is completely compatible with both old and current versions of ASP MVC (the blog uses old MVC markup, so you will need to update it to the RAZOR code for MVC3+).

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

The key component of this is the helper class "BeginCollectionItem", which handles the indexing of your list in a way that MVC will accept as a post-action parameter. Hope this helps.

Eckert
  • 690
  • 4
  • 9