2

I don't appear to be having the same issues as most with the implementation of BeginCollectionItem with MVC core, I'm not receiving any of the data.

I have this main page that has alot of work on it but here is the javascript that adds new sections to the page and the partial that will be added below.

@model QuizBuilderModel
...
function addSection() {
    $.ajax({
        url: '@Url.Action("AddSection","Quiz")',
        cache: false,
        success: function (html) {
        $("#sortable-survey").append(html);
        }
    });
}
...

<div class="quiz-builder" id="quiz-builder" style="@((Model.Quiz == null || string.IsNullOrEmpty(Model.Quiz.Id))? "display: none;" : "")">
        @{await Html.RenderPartialAsync("~/Views/Admin/Quiz/_QuizBuilder.cshtml", Model);}
</div>

Now, we have this partial to start the form we're building.

@model QuizBuilderModel

<div id="sortable-survey" class="sortable-survey">
    @using (Html.BeginForm("PostQuizUpdate", "Quiz", FormMethod.Post))
    {
        @if (Model.Quiz != null && !string.IsNullOrEmpty(Model.Quiz.Id))
        {
            <input type="submit" class="btn btn-lg btn-outline-primary top-right-button top-right-button-single" id="SaveQuizModal" name="SaveQuizModal" value="Save Quiz" />
        }

        @if (Model.Quiz != null && Model.Quiz.Sections != null)
        {
            foreach (Sections section in Model.Quiz.Sections)
            {
                await Html.RenderPartialAsync("~/Views/Admin/Quiz/_Section.cshtml", Model);
            }
        }
    }
</div>

<div>
    <div class="text-center">
        <button type="button" class="btn btn-outline-primary btn-sm my-5" id="AddSection" onclick="addSection();">
            <i class="simple-icon-plus btn-group-icon"></i>
            Add Section
        </button>
    </div>
</div>

Then I have this partial section where we'll be adding more and more to it.

@using HtmlHelpers.BeginCollectionItemCore
@model Sections

@using (Html.BeginCollectionItem("Sections"))
{
    <div class="form-group">
        @Html.LabelFor(x => x.Title);
        @Html.EditorFor(m => m.Title, new { @class = "form-control" })
    </div>

    <div class="form-group">
        <label>SubTitle (optional)</label>
        @Html.EditorFor(m => m.SubTitle, new { @class = "form-control" })
    </div>

    <div class="form-group">
        <label>Instructions (optional)</label>
        <textarea type="text" class="form-control" placeholder="" id="Instructions" name="Instructions" required rows="10" cols="50"></textarea>
    </div>
}

The response of the post is sent here...

[HttpPost]
public async Task<IActionResult> PostQuizUpdate(IEnumerable<Sections> Sections)
{
    ...
}

Like i said before when I hit the submit I'm not getting the list of Sections in the post.

jcaruso
  • 2,364
  • 1
  • 31
  • 64
  • Have you shown the correct code? You have a `foreach (Sections section ...)` line that is passing `QuizBuilderModel` to a partial that expect `Sections` which would throw [this exception](https://stackoverflow.com/questions/40373595/the-model-item-passed-into-the-dictionary-is-of-type-but-this-dictionary-requ) –  Nov 14 '18 at 00:10
  • @StephenMuecke ok I fixed that bug but I'm still getting zero rows. – jcaruso Nov 14 '18 at 02:33
  • Do you mean your `IEnumerable Sections` parameter in the POST method is `null` or an empty collection? –  Nov 14 '18 at 02:35
  • @StephenMuecke Empty collection... Count(0) – jcaruso Nov 14 '18 at 02:37
  • The rest of the code look OK, except you should be using `@Html.TextAreaFor(m => m.Instructions, new { ... })`. What is the actual html generated by one of the `_Section.cshtml` partials –  Nov 14 '18 at 02:40
  • I modified that but still nothing. – jcaruso Nov 14 '18 at 02:45
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/183598/discussion-between-stephen-muecke-and-jcaruso). –  Nov 14 '18 at 02:45

1 Answers1

1

Your script is appending the partial containing BeginCollectionItem to the <div id="sortable-survey" class="sortable-survey"> element. But that element contains your <form>....</form> element, so $("#sortable-survey").append(html); will append the html after the closing </form> tag, and as a result, your <form> itself will not contain any form controls, so there is nothing to submit.

Alter the html so that the <div> is within the <form> element

@using (Html.BeginForm("PostQuizUpdate", "Quiz", FormMethod.Post))
{
    <div id="sortable-survey" class="sortable-survey">
        ....
    </div>
}

so that the appended form controls are within the form tags.

As a side note, if your Sections property contains any existing elements, then your await Html.RenderPartialAsync("~/Views/Admin/Quiz/_Section.cshtml", Model); will throw a The model item passed into the dictionary is of type .. but this dictionary requires a model item of type exception. You need to modify the foreach loop to

foreach (Sections section in Model.Quiz.Sections)
{
    await Html.RenderPartialAsync("~/Views/Admin/Quiz/_Section.cshtml", section); // section, not Model
}

In addition, I recommend you initialize your collections in the controller before passing the model to the view so that you can delete the if null checks in the view.