Ajax 调用不在 MVC 中的嵌套编辑器模板内执行

问题描述 投票:0回答:1

我正在尝试创建一个用于创建/编辑测验的 Web 应用程序管理工具,该工具可以完全调整(使用 ASP.NET Core MVC)。

我所说的完全可调:

  1. 管理员用户可以在每个测验中添加/删除任意数量的问题。
  2. 管理员用户可以添加/删除每个问题答案的任何数字。

问题是,在

QuizViewModel
类中,我有一个
Questions
的集合,每个
Question
都有一个
Answers
的集合。

我已经通过使用 EditorTemplates 并对我的控制器方法执行 Ajax 调用,创建了 2 个用于添加和删除

Questions
的按钮,该方法在
Questions
集合中添加/删除对象。所有绑定都运行良好。

但是当我尝试为每个

Answer
添加/删除
Question
创建相同的逻辑时,就会出现问题。我试图通过分配每个答案的部分 div 来执行与
Questions
相同的操作,它是唯一的 id,即

string answersContainerId = $"answers-container-{Model.QuestionNumber}";

对“添加/删除答案”按钮执行相同的操作。

这是我的课程的简化结构:

public class QuizViewModel
{
    public string QuizName { get; set; }
    public List<QuizQuestion> Questions { get; set; }

    public QuizViewModel()
    {
        this.Questions = new List<QuizQuestion>
        {
            new QuizQuestion() // First must-have question
            {
                QuestionNumber = 1
            }
        };
    }
}
public class QuizQuestion
{   
    public string QuestionName { get; set; }
    public int Duration { get; set; } // Question duration (sec)
    public int QuestionNumber { get; set; }
    public List<QuizAnswer> Answers { get; set; } // List of answers per 1 question

    public QuizQuestion()
    {
        Duration = 30; // default
        Answers = new List<QuizAnswer>() // When creating a new empty question, by default we create 3 answers for it
        {
            new QuizAnswer{ AnswerNumber = 1 },
            new QuizAnswer{ AnswerNumber = 2 },
            new QuizAnswer{ AnswerNumber = 3}
        };
    }
}
public class QuizAnswer
{
    public string AnswerName { get; set; }
    public bool IsCorrect { get; set; }
    public int AnswerNumber { get; set; }
}

这是

Views>Quiz>CreateQuiz.cshtml
视图(简化):

@model QuizViewModel

@using (Html.BeginForm("CreateQuiz", "Quiz", FormMethod.Post, new { id = "form-create-new-quiz" }))
{
    @Html.AntiForgeryToken()

    <h3>Quiz Name:</h3>
    <div class="form-group">
        @Html.LabelFor(model => model.QuizName,"Quiz Name:", htmlAttributes: new { @class = "control-label" })
        @Html.TextBoxFor(model => model.QuizName, new { @class = "form-control"})
        @Html.ValidationMessageFor(model => model.QuizName, "", new { @class = "text-danger" })
    </div>
    
    <div>
        <h1>Quiz Questions:</h1>
        <div id="questions-container">
            @Html.EditorFor(model => model.Questions)
        </div>
    </div>
    
    <div>
        <button id="btn-add-new-question" type="button" class="btn btn-success">Add new question</button>
        <button id="btn-remove-quiz-question" type="button" class="btn btn-danger">Remove Question</button>
    
        <input type="submit" value="Submit Quiz" class="btn btn-primary" />
    </div>

}

@section Scripts 
{
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

    <script type="text/javascript">
        $("#btn-add-new-question").on('click', function () {
            $.ajax({
                async: true,
                data: $('#form-create-new-quiz').serialize(),
                type: "POST",
                url: "/Quiz/AddQuizQuestion",
                success: function (partialView) {
                    console.log("partialView: " + partialView);
                    $('#questions-container').html(partialView);
                }
            });
        });
    </script>
    
    <script type="text/javascript">
        $("#btn-remove-quiz-question").on('click', function () {
            $.ajax({
                async: true,
                data: $('#form-create-new-quiz').serialize(),
                type: "POST",
                url: "/Quiz/RemoveQuizQuestion",
                success: function (partialView) {
                    console.log("partialView: " + partialView);
                    $('#questions-container').html(partialView);
                }
            });
        });
    </script>
}

我有一个编辑器模板

.cshtml
文件,用于
Question
文件夹中的
Answer
EditorTemplates
类:

  1. Views>Shared>EditorTemplates>QuizQuestion.cshtml
    文件:
@model QuizQuestion

@{
    string currentQuestionAddAnswerButtonId = $"btn-add-new-answer-to-question-{Model.QuestionNumber}";
    string currentQuestionRemoveAnswerButtonId = $"btn-remove-answer-from-question-{Model.QuestionNumber}";
    string answersContainerId = $"answers-container-{Model.QuestionNumber}";
}

<div class="form-group">
    <div>
        @Html.LabelFor(question => question.QuestionName,"Question Name:", htmlAttributes: new { @class = "control-label" })
        @Html.TextBoxFor(question => question.QuestionName, new { @class = "form-control"})
        @Html.ValidationMessageFor(question => question.QuestionName, "", new { @class = "text-danger" })
    </div>

    <div id="@{@answersContainerId}">
        @Html.EditorFor(question => question.Answers)
    </div>

    <button id="@{@currentQuestionAddAnswerButtonId}" type="button" class="btn btn-success">Add New Answer</button>
    <button id="@{@currentQuestionRemoveAnswerButtonId}" type="button" class="btn btn-danger">Remove Answer</button>

</div>

@section Scripts
{
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

    <script type="text/javascript">
        $("#@{@currentQuestionAddAnswerButtonId}").on('click', function () {
            $.ajax({
                async: true,
                data: $('#form-create-new-quiz').serialize(),
                type: "POST",
                url: "/Quiz/AddNewAnswerToQuestion",
                success: function (partialView) {
                    console.log("partialView: " + partialView);
                    $('#@{@answersContainerId}').html(partialView);
                }
            });
        });
    </script>

    <script type="text/javascript">
        $("#@{@currentQuestionRemoveAnswerButtonId}").on('click', function () {
            $.ajax({
                async: true,
                data: $('#form-create-new-quiz').serialize(),
                type: "POST",
                url: "/Quiz/RemoveAnswerFromQuestion",
                success: function (partialView) {
                    console.log("partialView: " + partialView);
                    $('#@{@answersContainerId}').html(partialView);
                }
            });
        });
    </script>
}
  1. Views>Shared>EditorTemplates>QuizAnswer.cshtml
    文件:
@model QuizAnswer

<div>
    <h2><strong>Answer @Html.DisplayFor(answer => answer.AnswerNumber)</strong></h2>
    @Html.HiddenFor(answer => answer.AnswerNumber)

    <div class="form-group">
        <div>
            @Html.LabelFor(answer => answer.AnswerName,"Answer:", htmlAttributes: new { @class = "control-label" })
            @Html.TextBoxFor(answer => answer.AnswerName, new { @class = "form-control"})
            @Html.ValidationMessageFor(answer => answer.AnswerName, "", new { @class = "text-danger" })
        </div>

        <div class="form-check">
            @Html.CheckBoxFor(answer => answer.IsCorrect, new { @class = "form-check-input"})
            @Html.LabelFor(answer => answer.IsCorrect, "Is Correct", new { @class = "form-check-label"})
        </div>
    </div>
</div>

我确实有 2 个编辑器模板的部分视图:

  1. Views>Quiz>QuizQuestions.cshtml
@model QuizViewModel
@Html.EditorFor(model => model.Questions)
  1. Views>Quiz>QuizAnswers.cshtml
@model QuizQuestion
@Html.EditorFor(model => model.Answers)

最后,这是我的

QuizController
课程:

public class QuizController : Controller
{
    public IActionResult CreateQuiz()
    {
        return View(new QuizViewModel());
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> AddQuizQuestion([Bind("Questions")] QuizViewModel quizViewModel)
    {
        QuizQuestion newQuizQuestion = new QuizQuestion
        {
            QuestionNumber = quizViewModel.Questions.Count + 1
        };

        quizViewModel.Questions.Add(newQuizQuestion);
        return PartialView("QuizQuestions", quizViewModel);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> RemoveQuizQuestion([Bind("Questions")] QuizViewModel quizViewModel)
    {
        if (quizViewModel.Questions.Count is not 1)
        {
            quizViewModel.Questions.RemoveAt(quizViewModel.Questions.Count - 1);
        }

        return PartialView("QuizQuestions", quizViewModel);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> AddNewAnswerToQuestion([Bind("Questions")] QuizViewModel quizViewModel)
    {
        // Define to which question to add answer
        var quizQuestion = quizViewModel.Questions.FirstOrDefault();
        return PartialView("QuizAnswers", quizQuestion);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> RemoveAnswerFromQuestion([Bind("Questions")] QuizViewModel quizViewModel)
    {
        // Define from which question to remove answer
        var quizQuestion = quizViewModel.Questions.FirstOrDefault();
        return PartialView("QuizAnswers", quizQuestion);
    }
}

所以最后,当我按下独特的“添加/删除答案”按钮时,我的控制器方法

AddNewAnswerToQuestion()
RemoveAnswerFromQuestion()
不会被调用。

但是,相同的逻辑适用于添加/删除问题。

所以我认为问题出在嵌套类中。

真的希望有人能提供帮助,我一直在坚持这个问题。 如果您需要提供更多信息,请告诉我。

这是我在 Stack Overflow 上提出的第一个问题,所以如果有问题没有得到很好的解释,我深表歉意。

c# ajax asp.net-core-mvc model-binding mvc-editor-templates
1个回答
0
投票

我们可以看到,我们没有

<script>
Views>Shared>EditorTemplates>QuizQuestion.cshtml
,这意味着我们没有
Add New Answer
按钮的 onclick 事件处理程序。

这是因为在局部视图中,我们使用

@section Scripts{ }
包围脚本。让我们删除
@section Scripts{ }
中的
QuizQuestion.cshtml
并查看结果。

在点击添加答案按钮的控制器方法后,我停止了故障排除...

© www.soinside.com 2019 - 2024. All rights reserved.