Search code examples
c#asp.net-mvcasp.net-mvc-4t4mvc

MVC + T4MVC - How to pass a url action to form? Or an alternative method to generate action/id?


I'm looping through a model and iterating through data. I want to add a button on each item that generates an action/id.

As I cannot add a url to a button , I've decided to use a form with the following:

<form action="@Url.Action("ItemDetail", new { itemId = @quote.Item.ItemID})">
    <button class="btn-bg btn-sm btn-inverse btn-fix-width" type="submit">
        <i class="fa fa-th-list fa-fw pull-right"></i>View RFQ
    </button>
</form>

I opted for a button instead of input type to inset font-awesome icons.

However, I get /Quote/ItemDetail? as opposed to /Quote/ItemDetail?itemId=123

I'm using T4MVC

Controller:

public virtual ActionResult ItemDetail(int ItemID)
{
    return View();
}

RouteConfig:

routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

Solution

  • With T4MVC, something like this should work:

    <form action="@Url.Action(MVC.Quote.ItemDetail(quote.Item.ItemID))">
    

    ...Note that this is assuming the ItemDetail action is on your QuoteController. If the controller name is different, change Quote to whatever the name of your controller is.

    You could also go more with @Zaphod's comment and do something like this:

    <form action="@Url.Action(MVC.Quote.ActionNames.ItemDetail, MVC.Quote.Name,
        new { itemId = @quote.Item.ItemID})">
    

    ...at least here T4MVC gets rid of your magic strings, even if you are still using MVC's out of the box Url.Action overload.

    You should also name your action method arguments using camelCase, not PascalCase:

    public virtual ActionResult ItemDetail(int itemId) // instead of ItemID
    {
        return View();
    }
    

    ...though I don't think that should cause any issues.

    Update

    Try this maybe?

    <form method="GET" action="@Url.Action(MVC.Quote.ItemDetail(quote.Item.ItemID))">
    

    or this:

    <form method="GET" action="@Url.Action(MVC.Quote.ActionNames.ItemDetail, MVC.Quote.Name)">
        <input type="hidden" name="itemId" value="@quote.Item.ItemID" />
        <button class="btn-bg btn-sm btn-inverse btn-fix-width" type="submit">
            <i class="fa fa-th-list fa-fw pull-right"></i>View RFQ
        </button>
    </form>
    

    Another update:

    You should also be able to do this instead, and then use CSS to make your link look like a button:

    <a href="@Url.Action(MVC.Quote.ItemDetail(quote.Item.ItemID))">
        <i class="fa fa-th-list fa-fw pull-right"></i>View RFQ
    </a>
    

    IMHO, this is what you really should do, since you're only sending one parameter.