Home > other >  Why do I receive null values in my controller when I submit a form from a view with multiple forms?
Why do I receive null values in my controller when I submit a form from a view with multiple forms?

Time:12-31

I am developing a web application using ASP.NET Core 5 MVC, in which I seek to make multiple submissions of POST type forms to my controller from a view that receives an IEnumerable (from a model called Result) with which I am filling in dynamically the values of the inputs of each form.

However, when I send one of those forms from the view through the controller, in the controller I only receive an object from the model with all the null or empty values, which tells me that it seems that this data was never sent through the form to my controller.

Is there a better way to accomplish this or how do I pass these values from multiple forms to my controller? In advance an apology if what I am doing is already totally wrong, I have been learning ASP.NET Core MVC for a few days.

CONSIDERATIONS

What I seek to achieve is that the user can enter multiple values that belong to the same model in the same view, since each form although it is the same seeks to update a different record or column in the same model or table, so when the submit of the form is sent to the Controller the view does not change, and only the records in the database are updated with each submit in the view. If there is a better way or correct way to do this, I am willing to change the logic, because as I mentioned, I have been using the Framework for little.

Explained the problem and my goal, I will explain in greater detail the flow and code mentioned:

  1. From the Mechanical method of my controller, I return a list of Objects to their corresponding View, which are brought by a DataBaseContext:

     // CONTROLLER() that passes an enumerable list of Objects to View Mechanical.cshtml
     public IActionResult Mechanical()
     {
         IEnumerable<Result> objList = _db.Results;
         return View(objList);
     }
    
  2. In the Mechanical() view, I get this list of objects and iterate over it through a forEach() loop, where for each object I create a form that directs to the same controller method called Update(), in which I get the values of the object in null and empty (that being my problem):

// VIEW
@model IEnumerable<FatForm.Models.Result>

@if (Model.Count() > 0)
{
    @foreach(var result in Model)
    {
        <form method="post" asp-action="Update">
            <input asp-for="@result.Id" hidden />
            <input asp-for="@result.Type" hidden />
            <input asp-for="@result.FatId" hidden />
            <div >
                <div >
                    <h2 >Edit Result</h2>
                </div>
                <div >
                    <div >
                        <div >
                            <div >
                                <label asp-for="@result.Section"></label>
                            </div>
                            <div >
                                <label asp-for="@result.Procedure"></label>
                            </div>
                            <div >
                                <label asp-for="@result.ResultDescription"></label>
                            </div>
                            <div >
                                <label asp-for="@result.Passed"></label>
                            </div>
                        </div>
                        <div >
                            <div >
                                <input asp-for="@result.Section"  />
                            </div>
                            <div >
                                <input asp-for="@result.Procedure"  />
                            </div>
                            <div >
                                <input asp-for="@result.ResultDescription"  />
                                <span asp-validation-for="@result.ResultDescription" ></span>
                            </div>
                            <div >
                                <input asp-for="@result.Passed"  />
                                <span asp-validation-for="@result.Passed" ></span>
                            </div>
                        </div>
                        <div >
                            <div >
                                <div >
                                    <input type="submit"  value="Save" />
                                </div>
                            </div>
                        </div>

                    </div>
                </div>
            </div>
        </form>        
    }
}
else
{
    <p>No results created yet</p>
}

@section Scripts{
    @{
        <partial name="_ValidationScriptsPartial" />
    }
}
  1. I'm supposed to be looking to send the form values to the following Update() controller method, in which I get all the object values to null:

     // POST Update
     [HttpPost]
     [ValidateAntiForgeryToken]
     public IActionResult Update(Result obj)
     {
         if (ModelState.IsValid)
         {
             _db.Results.Update(obj);
             _db.SaveChanges();
             //return RedirectToAction("Index");
         }
    
         return View(obj);
     }
    

Here you can see the null values on the controller from the view

As I explained at the beginning, I hope can help me by indicating what I am doing wrong or in what way I should do it. Thanks in advance for your help.

CodePudding user response:

Here you need to add FromBody attribute in your action method parameter.

public IActionResult Update([FromBody]Result obj)
{
   .....
}

CodePudding user response:

Model binding looks through the sources for the name pattern prefix.property_name. If nothing is found, it looks for just property_name without the prefix.In your code,the asp-for tag helper will generate the name like:result.propertyName.It could not match with backend model. You need use [Bind(Prefix ="result")] to specify the prefix:

[HttpPost]
[ValidateAntiForgeryToken]

public IActionResult Update([Bind(Prefix ="result")]Result obj)
{
    //do your stuff...
}

As for receive IEnumerable parameter in action, firstly you need change your razor view to move the form outside the foreach loop, then you need change the asp-for tag helper tattribute to @Model.ToList()[index].PropertyName:

@model IEnumerable<Result>

@if (Model.Count() > 0)
{
    <form method="post" asp-action="Update">
        @for (int i = 0; i < Model.Count(); i  )
        {
            <input asp-for="@Model.ToList()[i].Id" hidden />
            <input asp-for="@Model.ToList()[i].Type" hidden />
            <input asp-for="@Model.ToList()[i].FatId" hidden />
            <div >
                <div >
                    <h2 >Edit Result</h2>
                </div>
                <div >
                    <div >
                        <div >
                            <div >
                                <label asp-for="@Model.ToList()[i].Section"></label>
                            </div>
                            <div >
                                <label asp-for="@Model.ToList()[i].Procedure"></label>
                            </div>
                            <div >
                                <label asp-for="@Model.ToList()[i].ResultDescription"></label>
                            </div>
                            <div >
                                <label asp-for="@Model.ToList()[i].Passed"></label>
                            </div>
                        </div>
                        <div >
                            <div >
                                <input asp-for="@Model.ToList()[i].Section"  />
                            </div>
                            <div >
                                <input asp-for="@Model.ToList()[i].Procedure"  />
                            </div>
                            <div >
                                <input asp-for="@Model.ToList()[i].ResultDescription"  />
                                <span asp-validation-for="@Model.ToList()[i].ResultDescription" ></span>
                            </div>
                            <div >
                                <input asp-for="@Model.ToList()[i].Passed"  />
                                <span asp-validation-for="@Model.ToList()[i].Passed" ></span>
                            </div>
                        </div>

                    </div>
                </div>
            </div>
        }
        <div >
            <div >
                <div >
                    <input type="submit"  value="Save" />
                </div>
            </div>
        </div>
    </form>
}
else
{
<p>No results created yet</p>
}

Controller:

[HttpPost]
[ValidateAntiForgeryToken]

public IActionResult Update(IEnumerable<Result> obj)
{
    return View("Mechanical", obj);
}

Result:

enter image description here

  • Related