foo bar
foo bar

Reputation: 180

ASP.net mvc5 multple actions on the same view?

I'm trying to have multiple actions accessible from my Index page instead of having a separate view for each. But I'm not having much luck and I'm pretty much stuck.

My BeginForm can't resolve action Create nor can it resolve the controller CategoriesController.

This is my controller:

public class CategoriesController : Controller
{
    private readonly ApplicationDbContext _db = new ApplicationDbContext();

    public async Task<ActionResult> Index()
    {
        return View(await _db.Categories.ToListAsync());
    }

    public ActionResult Create()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Create([Bind(Include = "Id,Name")] Category category)
    {
        if (ModelState.IsValid)
        {
            _db.Categories.Add(category);
            await _db.SaveChangesAsync();
            return RedirectToAction("Index");
        }

        return View(category);
    }

    public async Task<ActionResult> Delete(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        Category category = await _db.Categories.FindAsync(id);
        if (category == null)
        {
            return HttpNotFound();
        }
        return View(category);
    }

    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> DeleteConfirmed(int id)
    {
        Category category = await _db.Categories.FindAsync(id);
        _db.Categories.Remove(category);
        await _db.SaveChangesAsync();
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _db.Dispose();
        }
        base.Dispose(disposing);
    }
}

And this is my view

@using MultipleActionsSameView.Controllers
@model IEnumerable<MultipleActionsSameView.Models.Category>

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.ActionLink("Delete", "Delete", new { id=item.Id })
        </td>
    </tr>
}

</table> 

@using (Html.BeginForm("Create", "CategoriesController", FormMethod.Post))
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Category</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @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>
}

Upvotes: 0

Views: 1942

Answers (3)

BLoB
BLoB

Reputation: 9725

To have multiple submit buttons in one view do the following:

Create an attribute...

using System;
using System.Reflection;
using System.Web.Mvc;

/// <summary>
/// The MultipleButtonAttribute class is a custom attribute to cater for a view form with multiple submit buttons.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    /// <summary>Determines whether the action name is valid in the specified controller context.</summary>
    /// <param name="controllerContext">The controller context.</param>
    /// <param name="actionName">The name of the action.</param>
    /// <param name="methodInfo">Information about the action method.</param>
    /// <returns>True if the action name is valid in the specified controller context; otherwise, false.</returns>
    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var keyValue = string.Format("{0}:{1}", this.Name, this.Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[this.Name] = this.Argument;
            isValidName = true;
        }

        return isValidName;
    }

Then in the view I have multiple submit buttons and a form pointing at the index action like so...

@using (Html.BeginForm("Index", "Categories", FormMethod.Get, new { id = "mainForm" }))
{
    <input type="submit" value="Create" name="action:Create" />
    <input type="submit" value="Edit" name="action:Edit" />
}

Then in my controller:

[HttpGet]
[MultipleButton(Name = "action", Argument = "Create")]
public ActionResult Create()

[HttpGet]
[MultipleButton(Name = "action", Argument = "Edit")]
public ActionResult Edit()

Upvotes: 1

VJPPaz
VJPPaz

Reputation: 1015

use "Categories" instead of "CategoriesController"

 @using (Html.BeginForm("Create", "Categories", FormMethod.Post))
 {
      //your code
 }

sample here: BeginForm

Upvotes: 3

Mik
Mik

Reputation: 1354

Have you tried to drop the "Controller" suffix of "CategoriesController" in Html.BeginForm ?

Upvotes: 1

Related Questions