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

Ole Kristian Losvik picture Ole Kristian Losvik · Feb 15, 2016 · Viewed 23.9k times · Source

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.

Answer

Dealdiane picture Dealdiane · Feb 15, 2016

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