Можно ли заполнить viewmodel и сформировать сообщения об ошибках через ViewData []? - PullRequest
0 голосов
/ 09 апреля 2020

( Обновление: Я обнаружил, что Model в представлении доступно только для чтения, поэтому мое первоначальное представление о заполнении свойств модели с помощью ViewData невозможно. Любой другой обходной путь?)

У меня есть некоторые функции CRUD в качестве частичных представлений. Если отправленная форма недействительна, я не могу повторно отобразить форму с неполными данными. Можно ли это сделать?

В моем главном представлении проекта (Details.cs html) у меня есть это для отображения заметок этого проекта:

<partial name="_notes" model="@new ProjectNotesViewModel 
{ 
    ProjectId = Model.Id,
    Notes = Model.Notes, 
    ProjectNoteId = Model.ProjectNoteId, 
    ProjectNoteAction = Model.ProjectNoteAction,
    ProjectCompleted = Model.Completed
}" />

Это Метод контроллера "Details ()" для проекта:

public async Task<IActionResult> Details(int? id, int n, string a)
// n = ProjectNoteId, a = ProjectNoteAction ("c"=create, "e"=edit, "d"=delete, "v"=view (details))
{
    Project project = await db.Projects
        .Include(n => n.Notes)
        .Include(p => p.ParentProject)
        .Include(c => c.ChildProjects)
            .ThenInclude(o => o.ProjectOwner)
        .Include(o => o.ProjectOwner)
        .FirstOrDefaultAsync(m => m.Id == id);

    if (project == null) { return NotFound(); }

    ProjectViewModel vm = auto.Map<ProjectViewModel>(project);
    vm.ProjectNoteId = n;
    vm.ProjectNoteAction = a;
    vm.ProjectCompletedAction = a;
    return View(vm);
}

Частичное "_notes.cs html" соответствует Index.cs html для заметок проекта.

В _notes .cs html, у меня есть это:

@foreach (ProjectNoteViewModel note in Model.Notes)
{
    if (note.Id == Model.ProjectNoteId)
    {
        // Then we want to do something to this particular note:
        <tr class="alert-black-50">
            <td class="align-text-top text-light rounded-left" width="1">
                <span class="fas fa-clipboard fa-fw"></span>
            </td>
            <td class="pb-2 pr-2 text-light rounded-right">
                @if (Model.ProjectNoteAction == "v") // v = view (details)
                {
                    // View the details of the note
                    <partial name="_noteDetails" model="@note" />
                }
                @if (Model.ProjectNoteAction == "e") // = edit
                {
                    // Edit the note
                    <partial name="_noteEdit" model="@note" />
                }
                @if (Model.ProjectNoteAction == "d") // = delete
                {
                    // Delete the note
                    <partial name="_noteDelete" model="@note" />
                }
            </td>
        </tr>
    }
    else
    {
        // Just display the date and title:
        <tr>
            <td colspan="2">
                <a asp-action="Details" 
                    asp-route-n="@note.Id" 
                    asp-route-a="v">
                    <span class="fas fa-clipboard fa-fw"></span>
                    @note.Created &ndash; @note.Title
                </a>
            </td>
        </tr>
    }
}

Если мы, например, хотим создать новую заметку проекта, это то, где это происходит ("_noteCreate.cs html"):

@model Projects.Models.ProjectNoteViewModel

<form asp-action="CreateNote">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="ProjectId" />
    <div class="form-group">
        <label asp-for="Title" class="control-label"></label>
        <input asp-for="Title" class="form-control" />
        <span asp-validation-for="Title" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Contents" class="control-label"></label>
        <textarea asp-for="Contents" class="form-control"></textarea>
        <span asp-validation-for="Contents" class="text-danger"></span>
    </div>
    <div class="form-group">
        <a asp-action="Details" asp-route-id="@Model.ProjectId" class="btn btn-primary btn-split">
            <span class="fas fas-split fa-chevron-circle-left fa-fw"></span> Cancel
        </a>
        <button type="submit" class="btn btn-success btn-split">
            <span class="fas fas-split fa-save fa-fw"></span> Save
        </button>
    </div>
</form>

Метод контроллера «CreateNote»:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateNote(int projectId, [Bind("Title,Contents")] ProjectNote note)
{
    Project project = await db.Projects.Where(p => p.Id == projectId).FirstOrDefaultAsync();
    if (project == null)
    {
        return NotFound();
    }
    if (project.Completed)
    {
        // Prevent new notes from being created on completed projects.
        return RedirectToAction("Details", new { id = project.Id });
    }
    note.ProjectId = projectId;
    note.Created = DateTime.Now;
    if (ModelState.IsValid)
    {
        db.Add(note);
        await db.SaveChangesAsync();
        return RedirectToAction("Details", new { id = projectId });
    }

    ProjectNoteViewModel vm = auto.Map<ProjectNoteViewModel>(note);
    vm.Project = auto.Map<ProjectViewModel>(project);
    ViewData["draft"] = vm; // Can I somehow populate the form from ViewData?
    return RedirectToAction("Details", new { id = projectId });
    //return View(vm); // I can't do this, because there is no "CreateNote.cshtml"
}

Последние пять строк описанного выше метода - это то, что я не могу понять. В нормальной ситуации CRUD, где имя метода контроллера будет Create(), и у нас будет представление с именем «Create.cs html», это будет способ сделать это:

ProjectNoteViewModel vm = auto.Map<ProjectNoteViewModel>(note);
vm.Project = auto.Map<ProjectViewModel>(project);
return View(vm);

Но я не могу return View(), потому что нет представления с именем "CreateNote". Мне нужно вернуть пользователя в «Projects / Details / 5? A = c», где a=c (action = create) указывает, что мы создаем новую заметку для этого проекта. И я хочу взять с собой неполные данные формы.

...