Отправка одной из нескольких форм из шаблона редактора в действие контроллера - PullRequest
0 голосов
/ 05 апреля 2019

У меня есть приложение, которое показывает контрольный список с динамическим списком задач. На данный момент все задачи имеют 2 переключателя: один для Готово и один для Не выполнено. Я буду добавлять новые типы задач (текстовые поля и т. Д.) Позже.

Основной вид вызывает шаблон редактора, который создает каждую задачу. Модель контрольного списка хранит задачи в свойстве «Задачи» типа List<Task>. Это хорошо для отображения, но имеет проблемы при отправке формы.

Я хочу сохранить каждую задачу независимо, поэтому я поместил элемент <form> вокруг элементов управления в шаблоне редактора.

Контроллер

public class CheckController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        var checklist = new Checklist();
        GetData(checklist);
        return View(checklist);
    }

    [HttpPost]
    public ActionResult Index(Task model)
    {
        var task = (Task)model;
        return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
    }
}

Модель

public class Checklist
{
    public List<Task> Tasks { get; set; }
    public Checklist()
    {
        Tasks = new List<Task>();
    }
}

public class Task
{
    public int TaskId { get; set; }
    public string TaskName { get; set; }
    public bool IsDone { get; set; }
}

1020 * Просмотров *

@model Checkpoint.Models.Checklist
<table>
    @Html.EditorFor(x => x.Tasks);
</table>


@model Checkpoint.Models.Task
<tr>
    <td>@Model.TaskName</td>
    <td data-ftid="@Model.TaskId">
        @{
            using (Html.BeginForm("Index", "Check", FormMethod.Post))
            {
                @Html.HiddenFor(x => x.TaskId)
                @Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
                @Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
                <button role="button" type="submit" name="taskAction">Submit</button>
            }
        }
    </td>
</tr>

Визуализированный HTML

<tr>
    <td>First thing</td>
    <td>
        <form action="/Checklist" method="post">
            <input id="Tasks_0__TaskId" name="Tasks[0].TaskId" type="hidden" value="1" />
            <input checked="checked"id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="False" />
            <span>Incomplete</span>
            <input id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="True" 
            <span>Complete</span>
            <button role="button" type="submit" name="taskAction">Submit</button>
        </form>
    </td>
</tr>
<tr>
    <td>Second thing</td>
    <td>
        <form action="/Checklist" method="post">
            <input id="Tasks_1__TaskId" name="Tasks[1].TaskId" type="hidden" value="2" />
            <input checked="checked" id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="False" />
            <span>Incomplete</span>
            <input id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="True" />
            <span>Complete</span>
            <button role="button" type="submit" name="taskAction">Submit</button>
        </form>
    </td>
</tr>

Это отправляет запрос, но данные выглядят так:

Tasks[1].TaskId: 1
Tasks[1].IsDone: True

Когда оно достигает действия контроллера (которое принимает тип Task), значения свойства равны нулю.

Как правильно получить данные моей задачи в действии контроллера? Или я поступаю совершенно неправильно?

Бонус: какой будет лучший подход для добавления новых типов задач?

Ответы [ 2 ]

1 голос
/ 07 апреля 2019

Поскольку вы не пытаетесь опубликовать коллекцию в одном представлении, вам нужно потерять индекс по названию модели.

Tasks[0].TaskId

Настройте ваши взгляды. Имя переменной «задача» должно соответствовать параметру действия, поскольку HtmlHelpers будет генерировать атрибуты имени на основе этой строки.

@model Checkpoint.Models.Checklist
<table>
    @foreach(Task task in Model.Tasks)
    {
        @Html.EditorFor(m => task)
    }
</table>

Рендеринг HTML выглядит примерно так:

<input id="task_TaskId" name="task.TaskId" type="hidden" value="1">
...

Для действия требуется параметр "task" для сопоставления, чтобы связать его значения

[HttpPost]
public ActionResult Index(Task task)
{
    return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}

Если мы используем частичное представление вместо шаблона редактора, мы можем немного ослабить зависимость имени от «задачи».

@model Checkpoint.Models.Checklist
<table>
    @foreach(Task t in Model.Tasks)
    {
        @Html.PartialView("_TaskForm", t)
    }
</table>

И ваш шаблонный редактор будет работать точно так же.

_TaskForm

@model Checkpoint.Models.Task
<tr>
    <td>@Model.TaskName</td>
    <td data-ftid="@Model.TaskId">
        @{
            using (Html.BeginForm("Index", "Check", FormMethod.Post))
            {
                @Html.HiddenFor(x => x.TaskId)
                @Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
                @Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
                <button role="button" type="submit" name="taskAction">Submit</button>
            }
        }
    </td>
</tr>

и рендеринг HTML

<input id="TaskId" name="TaskId" type="hidden" value="1">
...

Гоча со всем вышеперечисленным атрибутом html id не будет уникальной. Поэтому, если это важно, вам нужно будет вручную выполнить итерацию коллекции, чтобы построить каждую форму вручную, чтобы вы могли точно указать значения идентификатора. То есть вы потеряете небольшой модульный редактор шаблонов.

Позволяя фреймворку автоматически генерировать "уникальные" идентификаторы ... мы перезаписываем атрибут name (обратите внимание на заглавную букву для "Name"), который мы имеем:

@model Checkpoint.Models.Checklist
<table>
    @for(int i = 0; i < Model.Tasks.Count; i++)
    {
        <tr>
           <td>@Model.Tasks[i].TaskName</td>
           <td data-ftid="@Model.Tasks[i].TaskId">
               @using (Html.BeginForm("Index", "Check", FormMethod.Post))
               {
                   @Html.HiddenFor(x => Model.Tasks[i].TaskId, new { Name="TaskId" })
                   @Html.RadioButtonFor(x => Model.Tasks[i].IsDone, false, new { Name="IsDone" })<span>Incomplete</span>
                   @Html.RadioButtonFor(x => Model.Tasks[i].IsDone, true, new { Name="IsDone" })<span>Complete</span>
                   <button role="button" type="submit" name="taskAction">Submit</button>
              }
           </td>
       </tr>
    }
</table>
0 голосов
/ 08 апреля 2019

Мне удалось выполнить эту работу с шаблоном редактора, убрав помощников и создав элементы управления вручную.

@model Checkpoint.Models.Task
<tr>
    <td>@Model.TaskName</td>
    <td data-ftid="@Model.TaskId">
        @using (Html.BeginForm("Index", "Check", FormMethod.Post))
        {
            <input name="TaskId" type="hidden" value="@Model.TaskId" />
            <input name="IsDone" type="radio" value="True" @Html.Raw(Model.IsDone ? "checked=checked" : null) />
            <span>Complete</span>
            <input name="IsDone" type="radio" value="False" @Html.Raw(!Model.IsDone ? "checked=checked" : null) />
            <span>Incomplete</span>
            <button role="button" type="submit" name="taskAction" value="@Model.TaskId">Submit</button>
        }
    </td>
</tr>

Я был не слишком доволен этим и вместо этого выбрал решение частичного просмотра @ Jasen. Мне удалось получить уникальные идентификаторы элементов, переопределив атрибут 'id' в помощнике. Я использовал TaskId, поскольку он уникален, но в противном случае мог бы передать индекс цикла из основного представления.

@model Checkpoint.Models.Task
<tr>
    <td>@Model.TaskName</td>
    <td data-ftid="@Model.TaskId">
        @using (Html.BeginForm("Index", "Check", FormMethod.Post))
        {
            @Html.HiddenFor(x => x.TaskId, new { id = "Task_" + Model.TaskId + "_hidIsDone" })
            @Html.RadioButtonFor(x => x.IsDone, false, new { id = "Task_"+ Model.TaskId + "_radIsDoneF" })<span>Incomplete</span>
            @Html.RadioButtonFor(x => x.IsDone, true, new { id = "Task_" + Model.TaskId + "_radIsDoneT" })<span>Complete</span>
            <button role="button" type="submit" name="taskAction">Submit</button>
        }
    </td>
</tr>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...