简体   繁体   中英

Razor Create Form for EF sub-object/navigation property collection?

Given an example object, say... Entry with a related object Comment where there is a foreign key from Comment to Entry called EntryID and is a collection (any number of comments for an entry), if a Razor page has a model of Entry and I want to have a form to create a new Comment , how would I do this? The scaffolded code is below and it would seem maybe I would say something like Comment.CommentText but that's not working because Comment is a collection...

//Code above this shows the Entry object as read-only followed by existing Comments, 
//I'm trying to allow the user to create a new comment
<div asp-validation-summary="ModelOnly" class="text-danger"></div> 
...       
    <div class="form-group">
        <label asp-for="CommentText" class="control-label"></label>
        <input asp-for="CommentText" class="form-control" />
        <span asp-validation-for="CommentText" class="text-danger"></span>
...

So what seems intuitive would be

<input asp-for="Comment.CommentText" class="form-control" />

but it's a collection so intellisense goes "Oh, this is a collection, here's some linq things and collection things."

How do?

If it's a collection you'll need a select tag like so:

   <select class="form-control" asp-for="Comment" asp-items="@(new SelectList(Model.Comment))"></select>

or

   <select class="form-control">
      @foreach(var c in Model.Comment)
      {
          <option>@c</option>
      }

   </select>

Updated-Insert New Comment You'll have to do a post on the form like so:

 <form asp-action="ControllerMethodName" id="formId" asp-controller="ControllerName"
     <div asp-validation-summary="ModelOnly" class="text-danger"></div>     
     <div class="form-group">
        <label asp-for="CommentText" class="control-label"></label>
        <input asp-for="CommentText" class="form-control" id="commentText" />
        <span asp-validation-for="CommentText" class="text-danger"></span>
        <input type="submit" value="Submit" class="btn btn-primary"/>
    </div>
 </form

Controller:

[HttpPost]
public async Task<IActionResult> ControllerMethodName (CommentViewModel model)
{
     await _svc.InsertComment(model); //_svc being your service layer=

     return RedirectToPage("./Index")

     //for return value

    var result = await _svc.InsertComment(model);

   return Json(result);
}

ViewModel:

 public class CommentViewModel
 {

     public string CommentText {get; set;}
 }

If you want to return a value to your html page, use the ajax or post method like so:

HTML:

  $('#formId').submit(function (e) {
        e.preventDefault();

        var comment = $('#commentText').val();

        $.ajax({
          url: '@Url.Action("ControllerMethodName", "ControllerName")',
          type: "POST",
          data: {"CommentText": comment},              

       }).done(function (data, textStatus, jqXHR) {
            //data will be your return value

       }).fail(function (data, textStatus, errorThrown) {

           //error handling
      });
   }

It seems the most straight-forward answer is to create a partial using the Comment object as a model, render a partial passing in a partially populated new Comment object as a model to the page.

Main/Parent Page:

@{ await Html.RenderPartialAsync("_CreateComment",new Comment() {  Entry.ID = Model.Id}); }

Partial:

<form asp-action="Create">
//form fields
<input type="submit" value="Create" class="btn btn-primary" />

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