81

I see references out there for @Html.Button(), but when I type that, IntelliSense doesn't find such a helper... there's dropdownlist, hidden, editors, et cetera, but no button!

Why is that?

TylerH
  • 20,799
  • 66
  • 75
  • 101
ekkis
  • 9,804
  • 13
  • 55
  • 105
  • 1
    Where do you see such references? – SLaks May 10 '11 at 20:03
  • 1
    I understand the desire for consistency but there's really no need for one (nothing to encode or protect against) so all it would be is a long-hand way to write a single html tag: '@Html.Button("myButton", new { @class = "myClass"})' vs '' – Russell Horwood Jan 08 '15 at 15:57
  • 4
    @Russel - I would disagree - I have created extension methods on MvcHtmlString to disable, make readonly, and hide DOM elements. Because there is no HTML helper for buttons I cannot use my extension methods. To say 'there is no need' is a bit short-sighted and possibly naive. – barrypicker Aug 26 '15 at 17:36

5 Answers5

70

I have written my own HTMLButton extension that you can use, instead:

public static class HtmlButtonExtension 
{

  public static MvcHtmlString Button(this HtmlHelper helper, 
                                     string innerHtml, 
                                     object htmlAttributes) 
  { 
    return Button(helper, innerHtml,
                  HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)
    ); 
  }

  public static MvcHtmlString Button(this HtmlHelper helper, 
                                     string innerHtml,
                                     IDictionary<string, object> htmlAttributes)
  {
      var builder = new TagBuilder("button");
      builder.InnerHtml = innerHtml;
      builder.MergeAttributes(htmlAttributes);
      return MvcHtmlString.Create(builder.ToString());
  }
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
jessegavin
  • 74,067
  • 28
  • 136
  • 164
  • I get the following error when using the above code: `'HtmlHelper' does not contain a definition for 'Button' and no extension method 'Button' accepting a first argument of type 'HtmlHelper' could be found (are you missing a using directive or an assembly reference?) ` I put the extension in the `namespace System.Web.Mvc.Html` – Legends Apr 29 '16 at 12:06
9

To expand on the accepted answer, so you can bind a submit button to a model property but have different text:

@Html.ButtonFor(m => m.Action, Model.LabelForCurrentAction(), new { @class = "btn btn-primary btn-large", type = "submit" })

Using the following slightly modified Button helper class:

/// <summary>
/// Via https://stackoverflow.com/questions/5955571/theres-no-html-button
/// </summary>
public static class HtmlButtonExtension
{

    public static MvcHtmlString Button(this HtmlHelper helper, object innerHtml, object htmlAttributes)
    {
        return helper.Button(innerHtml, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString Button(this HtmlHelper helper, object innerHtml, IDictionary<string, object> htmlAttributes)
    {
        var builder = new TagBuilder("button") { InnerHtml = innerHtml.ToString() };
        builder.MergeAttributes(htmlAttributes);
        return MvcHtmlString.Create(builder.ToString());
    }

    public static MvcHtmlString ButtonFor<TModel, TField>(this HtmlHelper<TModel> html,
                                                        Expression<Func<TModel, TField>> property,
                                                        object innerHtml,
                                                        object htmlAttributes)
    {
        // lazily based on TextAreaFor

        var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

        var name = ExpressionHelper.GetExpressionText(property);
        var metadata = ModelMetadata.FromLambdaExpression(property, html.ViewData);

        string fullName = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

        ModelState modelState;
        if (html.ViewData.ModelState.TryGetValue(fullName, out modelState) && modelState.Errors.Count > 0)
        {
            if( !attrs.ContainsKey("class") ) attrs["class"] = string.Empty;
            attrs["class"] += " " + HtmlHelper.ValidationInputCssClassName;
            attrs["class"] = attrs["class"].ToString().Trim();
        }
        var validation = html.GetUnobtrusiveValidationAttributes(name, metadata);
        if(null != validation) foreach(var v in validation) attrs.Add(v.Key, v.Value);

        string value;
        if (modelState != null && modelState.Value != null)
        {
            value = modelState.Value.AttemptedValue;
        }
        else if (metadata.Model != null)
        {
            value = metadata.Model.ToString();
        }
        else
        {
            value = String.Empty;
        }

        attrs["name"] = name;
        attrs["Value"] = value;
        return html.Button(innerHtml, attrs);
    }
}
Community
  • 1
  • 1
drzaus
  • 24,171
  • 16
  • 142
  • 201
9

There is no button helper as of mvc preview 3 (not mvc3)

it was mentioned a bunch in the past for example: http://blog.wekeroad.com/blog/aspnet-mvc-preview-using-the-mvc-ui-helpers/ however rolling your own is trivial - essentially just create a new Html.ButtonFor and copy the source code from Html.LabelFor and change the output to create an <input type="button"> tag.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
8

MVC5 , Bootstrap ver 3.2.0

@Html.ActionLink
(
    linkText: " Remove", 
    actionName: "Index", 
    routeValues: null, // or to pass some value -> routeValues: new { id = 1 },
    htmlAttributes: new { @class = "btn btn-success btn-sm glyphicon glyphicon-remove" }
)

This will generate a link that looks like a button.

Piotr Knut
  • 350
  • 3
  • 8
1

Razor does not appear to have a "Button" HTML helper. You're likely finding references to a custom-built HTML helper extension.

See here: http://www.asp.net/mvc/tutorials/creating-custom-html-helpers-cs

Ben Finkel
  • 4,753
  • 7
  • 34
  • 49
  • 1
    doesn't that seem bizarre? especially if it's trivial, why not include it for completeness?? – ekkis May 11 '11 at 04:36
  • I've read through that doc but I can't make it work. I've placed my helper in a file called HtmlHelpers.cs in the root of the project and it contains a static class HtmlHelpers with a public static method that returns a string whose only parameter is "this HtmlHelper helper". everything compiles and the .Button should appear in Intellisense but it doesn't... what else am I supposed to do? – ekkis May 11 '11 at 05:11
  • 1
    did you include the import statement for your extension namespace at the top of your view? thats the usual issue here. you may want to make sure your views compile (right click on project, select unload. right click to edit the file - set MvcBuildViews to true. save and close, and right click and reload project and compile again. – Adam Tuliper May 11 '11 at 05:30
  • I've moved the file into the Views/Shared folder and renamed it Helpers (the class too) but no dice... I'm using "namespace Website" which is my app's namespace and (I think) should thus be included in every view but I still can't get it to work. grr... what could it be? – ekkis May 11 '11 at 05:40
  • @Adam, I tried unloading the project... unfortunately, I've got some Visual Studio "explorer" extension that blew up "The operation could not be completed. Not implemented." and I had to kill VS. I'm not using a separate namespace... do I need to do that? – ekkis May 11 '11 at 05:43
  • @Adam, now I'm messed up. I can't reload the project, when I try it complains "A project with that name is already opened in the solution." thoughts? – ekkis May 11 '11 at 05:53
  • I disabled the Productivity Power Tools and restarted VS but I still couldn't get it to load the project. I found an SO article that suggested deleting the .suo file which fixed it (ooph). – ekkis May 11 '11 at 06:01
  • 1
    create a folder called extensions. add the htmlextensions.cs class there (making sure the namespace is correct) and then in your view use: @using Yourapp.Extensions also enable the MvcBuildViews using notepad if you are having an issue. – Adam Tuliper May 11 '11 at 06:15
  • MvcBuildViews is cool. though once I try to compile the project I got the error: "Could not load type 'System.Data.Entity.Design.AspNet.EntityDesignerBuildProvider'" from my web.config. I found an [http://stackoverflow.com/questions/2762256/mvcbuildviews-true-with-entity-framework-in-asp-net-mvc-2](SO article) that indicated I needed to include an assembly reference ``, however that just leads to another error... – ekkis May 11 '11 at 06:20
  • ..."It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level", which I have yet to figure out. there are suggestions out there that having two Web.Config files (maybe having one in a subfolder) will cause this but that's not my problem. there's also talk of having to configure your app for IIS, though I'm deploying to IIS Express without a problem so I'm not sure that's the issue... – ekkis May 11 '11 at 06:22
  • 1
    Ekkis, Not sure what you've done to your project but you need to do the following to create an HtmlHelperExtension: 1) Create a static class (I call mine HtmlHelperExtensions) 2) Within that class make public methods, annotated as , with the proper signature. 3) Return MvcHtmlString.Create(). See this post for a useful and functional example: http://stackoverflow.com/questions/4896439/action-image-mvc3-razor – Ben Finkel May 11 '11 at 15:05
  • ok, I got it all to work. I found that under the obj\ directory there were several other copies of the Web.Config so I blew away the whole directory and recompiled (I did have to add the assembly reference indicated above). Everything worked great! – ekkis May 11 '11 at 18:24
  • In summary, it doesn't matter what namespace the your class that contains your HtmlHelper methods is in. What matters is that the view has access to that namespace. I (wrongfully) assumed views would have access to my application's namespace. I decided in the end to use Website.HtmlHelpers, but could have just as easily used just Website. Thanks everyone for the help! – ekkis May 11 '11 at 18:26
  • @Ben Finkel, excellent article. now that I've got the mechanism to work I have a template for building these things. thanks so much. – ekkis May 11 '11 at 18:27