Asp.net core form always returns null

Viewed 415

I'm trying to build one view that includes all (Create, Edit, Delete, and Index) in one View which is Index.

The problem is with Editing. Always returns null to the controller as shown in the gif.

enter image description here

I have Model and ViewModel as follows.

The Model BootstrapCategory

public class BootstrapCategory
{
    [Key]
    public Guid Id { get; set; }

    [MaxLength(20)]
    [Required]
    public string Category { get; set; }
}

The ViewModel VMBPCategoris

public class VMBPCategoris
{
    public List<BootstrapCategory> bootstrapCategories { get; set; }
    public BootstrapCategory bootstrapCategory { get; set; }
}

The View

Note: Edit not by the usual button in the table it instead by another button as shown in the gif

@model VMBPCategoris

        @foreach (var item in Model.bootstrapCategories)
        {
            <tr>
                <td>

                    <form asp-action="Edit" method="post">
                        <input type="hidden" asp-for="@item.Id" />
                        <div class="@item.Id d-none">
                            <div class="input-group">
                                <input id="btnGroupEdit" type="submit" value="Save" class="input-group-text btn btn-primary" />
                                <input asp-for="@item.Category" class="form-control" aria-label="Input group example" aria-describedby="btnGroupEdit">
                            </div>
                            <span asp-validation-for="@item.Category" class="text-danger"></span>
                        </div>
                    </form>

                    <div class="@item.Id">
                        @Html.DisplayFor(modelItem => item.Category)
                    </div>

                </td>
                <td>
                    <a href="@item.Id" class="ToggleEdit">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
                </td>
            </tr>
        }

The Controller

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit([Bind("Id,Category")] BootstrapCategory bootstrapCategory)
{

    _context.Update(bootstrapCategory);
    await _context.SaveChangesAsync();

    return RedirectToAction(nameof(Index));
    //return View(vMBPCategoris);
}
3 Answers

The view model class VMBPCategoris needs to have its members properties assigned to instances in a constructor:

public class VMBPCategoris
{
    public List<BootstrapCategory> bootstrapCategories { get; set; }
    public BootstrapCategory bootstrapCategory { get; set; }

    public VMBPCategoris()
    {
        bootstrapCategories = new List<BootstrapCategory>();
        bootstrapCategory = new BootstrapCategory();    
    }
} 

You can give a name to your input tag.Change your form like below.

<form asp-action="Edit" method="post">
        <input type="hidden" asp-for="@item.Id" name="Id"/>
            <div class="@item.Id d-none">
                <div class="input-group">
                     <input id="btnGroupEdit" type="submit" value="Save" class="input-group-text btn btn-primary" />
                     <input asp-for="@item.Category" name="Category" class="form-control" aria-label="Input group example" aria-describedby="btnGroupEdit">
                </div>
                     <span asp-validation-for="@item.Category" class="text-danger"></span>
            </div>
 </form>

I made an easy solution by changing a little bit with the ViewModel and using the value attribute to get value from a model and using asp-for to set a value to another model.

It's all clarified in that Stackoverflow post

Related