stuck
stuck

Reputation: 3

How to add objects to list in view and post modified list back to controller? (ASP .NET core wirth mvc)

My purpose is to create edit page with complex model, where I can also add objects to the existing list, with possibility to change other fields and then post all data back to controller and save changes (or new objects) to database. I am using ASP .NET core 3 with mvc.

My edit page displays some info about user and also list of relatedData. I want related data list to be fully editable, user should be able to add or delete object from relatedDataList.

Here is what I have tried, I am not sure wether it is right approach. However newly inserted data are just added to the table, they are not posted back to the controller, validation doesnt work for them too.

My another question is how could I effectively calculate sum of values from related data list, after any change in table with related data (before submitting form).

Any ideas how to solve this are fully appreciated, thank you for your time!

ObjectViewModel.cs

 public class ObjectViewModel
{
    public User user{ get; set; }
    public double SomeCountedValue{ get; set; } //not stored in db
    ...
    public List<RelatedData> RelatedDataList{ get; set; }
}

RelatedData.cs

public class RelatedData
{
    public int Id { get; set; }

    public string Type { get; set; }

    [Required]
    public double Value { get; set; }

    ...some other data

    public int UserId { get; set; }
}

EditPage.cshtml

@model ViewModels.ObjectViewModel

   <form asp-action="Edit">
       //here i edit user data
       ...

       <table>
           <thead>
           ...
           </thead>
           <tbody id="relatedDataTableBody">
               @for (int i = 0; i < Model.RelatedDataList.Count; i++)
               {
                  <partial name="../Shared/Editors/_RelatedDataEditor.cshtml" for="@Model.RelatedData[i]" />
               }
          </tbody>
      </table>
      <button type="button" id="addRelatedData">Add</button>
      ...
      <input type="submit" value="save"/>
   </form>
   <script>...
       $("#addRelatedData").click(function () {
           $.ajax({
               url: "/UserController/AddRelatedData",
               cache: false,
               success: function (html) {$("#relatedDataTableBody").append(html); }
           });
           return false;
       });...
  </script>

UserController

public PartialViewResult AddRelatedData()
        {
            return PartialView("../Shared/_RelatedDataEditor", new RelatedData());
        }

 [HttpPost]
 [ValidateAntiForgeryToken]
 public IActionResult Edit(ObjectViewModel model)
 {
    if (ModelState.IsValid)
    {
         //save all changes
    }else{
       return View(model);
    }
  return RedirectToAction(nameof(Index));
}

_RelatedDataEditor.cshtml

@model Models.RelatedData

<tr class="tr">
      <td>
          <input hidden asp-for="@Model.Id" />
      <td>
          <input asp-for="@Model.Type" class="form-control"/>
          <span asp-validation-for="@Model.Type" class="text-danger"></span>
      </td>
  ...
      <td>
          <a value="Delete" onclick="$(this).closest('.tr').remove();">delete</a>
      </td>
</tr> ```

Upvotes: 0

Views: 5184

Answers (1)

Nan Yu
Nan Yu

Reputation: 27538

The first thing is it should be :

<partial name="" for="@Model.RelatedDataList[i]" />

Instead of :

<partial name="" for="@Model.RelatedData[i]" />

You are using Ajax to load the partial view , if you want to implement model binding , as workaround , you can append the html from partial view and set the current index like :

$("#addRelatedData").click(function () {

    var lastID = $("#relatedDataTableBody tr:last").children("td:first").find("input").eq(0).attr("id");
    var id =  parseInt(lastID.split("_")[1]) + 1;

    var html ="<tr class='tr'><td><input hidden='' type='number' data-val='true' data-val-required='The Id field is required.' id='RelatedDataList_"+id+"__Id' name='RelatedDataList["+id+"].Id'></td>"
    html += "<td><input class='form-control' type='text' id='RelatedDataList_" + id + "__Type' name='RelatedDataList[" + id + "].Type' >";
    html +="<span class='text-danger field-validation-valid' data-valmsg-for='RelatedDataList["+id+"].Type' data-valmsg-replace='true'></span></td>"
    html +="<td><a value='Delete' onclick=\"$(this).closest('.tr').remove();\">delete</a></td></tr>"
    $("#relatedDataTableBody").append(html);
});

Upvotes: 2

Related Questions