Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Submit form and do controller action from ViewComponent in ASP.NET Core

I want to add ListItems from a form in a ViewComponent in an ASP.NET 5, Mvc core application.

The component view (Views\Shared\Components\AddListItem\Default.cshtml):

@model ShoppingList.Models.ListItem
<form asp-action="Create">
    <div class="form-horizontal">
        <hr />
        <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>
        <!-- some fields omitted for brevity -->
        <div class="form-group">
            <label asp-for="Description" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Description" class="form-control" />
                <span asp-validation-for="Description" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

The ViewComponent controller (ViewComponents\AddListItem.cs):

namespace ShoppingList.ViewComponents
{
    public class AddListItem : ViewComponent
    {
        private readonly ApplicationDbContext _context;

        public AddListItem(ApplicationDbContext context)
        {
            _context = context;
        }

        public IViewComponentResult Invoke(string listId)
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IViewComponentResult> Create (ListItem listItem)
        {
            _context.ListItem.Add(listItem);
            await _context.SaveChangesAsync();
            return View(listItem);
        }

    }
}

The Component is invoked in home.cshtml:

@{
        ViewData["Title"] = "Home Page";
}

@Component.Invoke("AddListItem", @ViewBag.DefaultListId)

However, I cannot get this to work. Nothing is added.

like image 354
Ole Kristian Losvik Avatar asked Feb 14 '16 23:02

Ole Kristian Losvik


2 Answers

Rename AddListItem to AddListItemViewComponent. This is a convention that is used by ASP.NET to find the component - that is ViewComponents need to end with a ViewComponent suffix. If you don't want to do it this way, you could decorate the class with the [ViewComponent] attribute and set the name property to whatever name you require.

Also, the Create method will never be invoked and ViewComponents will never respond to an HttPost because it's only purpose is to display view and not to execute code in response to a postback. The View will only either call Invoke or its asynchronous version InvokeAsync and nothing else.

It's a bit confusing at first but an easy way to think about it is like a powerful Partial in the sense that you can do more stuff in the component class, DI friendly, and is easier to test as well.

The ASP.NET team has a page that explains ViewComponents here

like image 135
Dealdiane Avatar answered Nov 17 '22 07:11

Dealdiane


Thanks for your help, @Dealdiane.

In case anyone intested, here is the working code:

Views\Shared\Components\AddListItem\Default.cshtml

<form asp-controller="ListItems" asp-action="QuickCreate">
    <div class="form-horizontal">
        <hr />
        <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>

        <div class="form-group">
            <label asp-for="No" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="No" class="form-control" />
                <span asp-validation-for="No" class="text-danger" />
            </div>
        </div>
 ...

Controllers\ListItemsController.cs

    // POST: ListItems/QuickCreate
    // Create item without showing view, return to home 
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> QuickCreate(ListItem listItem)
    {
            _context.ListItem.Add(listItem);
            await _context.SaveChangesAsync();
            return Redirect("/"); 
    }
like image 8
Ole Kristian Losvik Avatar answered Nov 17 '22 05:11

Ole Kristian Losvik