简体   繁体   中英

Data-binding for collections in Create View of ASP.NET MVC

I'm trying to add a survey feature to my ASP.NET MVC 5 web application so that users can create surveys with custom questions to send out to other users. The problem is, I'm having trouble allowing users to add questions to the survey on the Create Survey view.

I've seen ways to do this on the "Edit" View, when an instance of the model has already been created, but I want the user to be able to create questions on the survey before adding the survey to the database.

This is my Survey Model:

public class Survey
    {
        public int SurveyId { get; set; }

        public string Name { get; set; }

        public string Author { get; set; }

        public DateTime StartDate { get; set; }

        public DateTime EndDate { get; set; }

        public List<Question> Questions { get; set; }

        public List<Response> Responses { get; set; }
    }

and this is my Question model:

public class Question
    {
        public int QuestionId { get; set; }

        public int SurveyId { get; set; }

        public string Title { get; set; }

        public string Body { get; set; }

        public QuestionType QuestionType { get; set; }

        public DateTime CreatedOn { get; set; }

        public DateTime LastModified { get; set; }

        public List<Answer> Answers { get; set; }
    }

Honestly, the code I have right now in Create.cshtml is garbage because I don't really know where to start but here it is anyways:

<h2>Create</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Survey</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Author, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Author, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Author, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.StartDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.StartDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.StartDate, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.EndDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.EndDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.EndDate, "", new { @class = "text-danger" })
            </div>
        </div>

        <h4 class="well well-small">
            Questions
        </h4>

        <button class="toggle-add-question" data-target="#add-question" data-toggle="modal" type="button">
            <i class="icon-plus"></i> Add Question
        </button>

        <div class="modal" id="add-question" tabindex="-1">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h3>Add Question</h3>
            </div>
            <div class="modal-body">
                <div class="row">
                    <form method="post">
                        <fieldset>
                            <div class="form-group">
                                <label for="Title">Title</label>
                                <input type="text" id="Title" name="Title" data-bind="value: title" />
                            </div>
                            <div class="form-group">
                                <label for="Type">Type</label>
                                <select id="Type" name="Type" data-bind="value: type">
                                    <option>Yes/No</option>
                                    <option>Number</option>
                                </select>
                            </div>
                        </fieldset>
                        <div class="form-group">
                            <div class="col-md-offset-2 col-md-10">
                                <input type="submit" value="Create" class="btn btn-default" data-dismiss="modal" />
                            </div>
                        </div>
                    </form>
                </div>
                <div class="row">
                    <div class="span6">
                        <textarea id="Body" name="Body"></textarea>
                    </div>
                </div>
            </div>
        </div>

        <table class="table">
            <tr>
                <th>
                    Question Title
                </th>
                <th>
                    Question Body
                </th>
                <th>
                    Question Type
                </th>
            </tr>
            @if (Model.Questions != null)
            {
                for (var i = 0; i < Model.Questions.Count(); i++)
                {
                    <tr>
                        @Html.HiddenFor(x => Model.Questions[i].QuestionId)
                        <td>
                            @Html.TextBoxFor(x => Model.Questions[i].Title)
                        </td>
                        <td>
                            @Html.TextBoxFor(x => Model.Questions[i].Body)
                        </td>
                        <td>
                            @Html.TextBoxFor(x => Model.Questions[i].QuestionType)
                        </td>
                    </tr>
                }
            }
        </table>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

What I want is for the user to be able to click the "Add Question" button, have the modal with the question fields pop up, and then for the user to be able to click "save" and have the modal exit and the new question appear in the table. Right now, I'm getting the error that the object reference is not set to an instance of the object, which makes perfect sense because the Survey object hasn't been created yet, but I'm unsure of how to do this differently. (Without the table, the modal view pops up and everything but no questions are added).

Any help would be greatly appreciated, thanks!

You could update the table, when saving the modal popup by combining AJAX and Partial Views (called partials from here on).

The table that holds your question data could sit in a partial with its own view model that takes in the questions you want to render. You can keep the markup as is.

On your page, where the table is now, replace that with a containing div that has the partial inside.

When you save the modal that adds a new question, you could use an AJAX call (trigger on click) to hit your Controller, save the new question record (with whatever validation you need) and return the table partial with a new view model, populated with the questions in your DB (which would include the new you just saved).

In the success callback of the AJAX call, populate the container div with the new partial and view model, then close the popup. The page will show a new question in the table without having go through a whole page cycle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM