21

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.

2
  • How are you calling this ViewComponent? Commented Feb 15, 2016 at 1:32
  • @{ ViewData["Title"] = "Home Page"; } @Component.Invoke("AddListItem", @ViewBag.DefaultListId) Commented Feb 15, 2016 at 7:08

2 Answers 2

18

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

Sign up to request clarification or add additional context in comments.

6 Comments

I think the link changed or that section is no longer available... learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components
You mean I can not call HttpPost method in viewcomponent?
@AProgrammer, that's correct. ViewComponents are designed to render stuff and not to process requests.
but how do you then handle a ViewComponent where it has functionality which is specific to the ViewComponent.... like a control which has search... where do you put the search action....
Is there some alternative where I can use HttpPost request on partial component? I need have selectlist - dropdownlist on viewcomponent or partialview.
|
9

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("/"); 
    }

1 Comment

The link is 404

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.