Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating MVC Delete button extension - How To Extend MVC's Html helper?

ASP.NET MVC 2 renders a link (i.e. <a>) to delete records.

It can be harmful to allow delete actions through GET actions, so I want to do the delete by issuing a POST.

I've created the following piece of code:

<% using (Html.BeginForm("Delete", "Boodschap", new { id = item.BoodschapID }))
    { %>
    <button>Delete</button>
<% } %>

Now I would like to add this code to the Html helper as an extension method:

public static MvcForm DeleteButton(this HtmlHelper helper, string name, 
    string actionName, string controllerName, string routeValues)
{
    MvcForm form = helper.BeginForm(actionName, controllerName, routeValues);
    return form;
}

Now here is where I got stuck. How do I get this delete button to work?

like image 464
Kees C. Bakker Avatar asked Nov 12 '11 15:11

Kees C. Bakker


2 Answers

If you want to generate the full code, you're going about it wrong to have it return an MvcForm. You want to have it return an MvcHtmlString and construct the HTML within the method. That way you can use it as:

@Html.DeleteButton( "Delete", "Boodschap", new { id = item.BoodschapID } );

Generating the HTML directly (note: untested, you may need suitable null checks, etc.)

public static MvcHtmlString DeleteButton( this HtmlHelper helper, string name, 
    string actionName, object htmlAttributes )
{
     return DeleteButton( helper, name, actionName, null, null, htmlAttributes );
}

public static MvcHtmlString DeleteButton( this HtmlHelper helper, string name, 
    string actionName, string controllerName, object routeValues, 
    object htmlAttributes )
{
     var buttonBuilder = new TagBuilder("button");
     buttonBuilder.SetInnerText( name );

     var formBuilder = new TagBuilder("form");
     var urlHelper = new UrlHelper( helper.ViewContext.RequestContext );
     formBuilder.Attributes.Add( "action", urlHelper.Action( 
         actionName, controllerName, routeValues ) )
     formBuilder.Attributes.Add( "method", FormMethod.Post );
     formBuilder.MergeAttributes( new RouteValueDictionary( htmlAttributes ) );
     formBuilder.InnerHtml = buttonBuilder.ToString();

     return new MvcHtmlString( formBuilder.ToString() );
}

An alternative would be to reuse the form helpers and Response.Write, but have the method return an (empty) string, perhaps something like:

public static MvcHtmlString DeleteButton(this HtmlHelper helper, string name, string actionName, object routeValues)
{
    return DeleteButton(helper, name, actionName, null, routeValues, null);
}

public static MvcHtmlString DeleteButton(this HtmlHelper helper, string name, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
    using (helper.BeginForm(actionName, controllerName, routeValues, FormMethod.Post, htmlAttributes))
    {
        var response = helper.ViewContext.HttpContext.Response;
        var builder = new TagBuilder("button");
        builder.SetInnerText(name);
        response.Write(builder.ToString(TagRenderMode.Normal));
    }
    return MvcHtmlString.Create("");
}
like image 114
tvanfosson Avatar answered Oct 16 '22 12:10

tvanfosson


While I think that a <form> element will do the trick, it isn't very AJAX-y.

Rather, why not use jQuery, wire up to the click event for the appropriate <a> links, and then issue an HTTP POST to the server yourself?

$document.ready(function () {
    // "deleteLink is a class that identifies links that
    // are used for deleting, you might have some other mechanism
    $("a .deleteLink").click(function () { 
        $.post('post url', function(data) {
            // Do something with the data returned
        });    
    });
});

The advantage to this is you keep your HTML much cleaner than if you inserted a <form> for every item you wanted to delete, and semantically-relevant, clean markup is always a plus from a development, SEO and other perspectives.

like image 1
casperOne Avatar answered Oct 16 '22 14:10

casperOne