2009-05-23 7 views
11

¿Alguien ha escrito uno? Quiero que se comporte como un enlace pero se vea como un botón. Un formulario con un solo botón no lo hará si no quiero ningún POST.Mvc Html.ActionButton

Respuesta

17

La forma más sencilla de hacerlo es tener una pequeña form etiqueta con method="get", en el que se coloca un botón de envío:

<form method="get" action="/myController/myAction/"> 
    <input type="submit" value="button text goes here" /> 
</form> 

Por supuesto, puede escribir un método de extensión muy simple que toma el texto del botón y un RouteValueDictionary (o un tipo anónimo con los valores de ruta) y crea el formulario para que no tenga que volver a hacerlo en todas partes.

EDITAR: En respuesta a la respuesta de cdmckay, aquí hay un código alternativo que utiliza la clase TagBuilder en lugar de un habitual StringBuilder para construir la forma, sobre todo para mayor claridad:

using System.Web.Mvc; 
using System.Web.Mvc.Html; 
using System.Web.Routing; 

namespace MvcApplication1 
{ 
    public static class HtmlExtensions 
    { 
     public static string ActionButton(this HtmlHelper helper, string value, 
           string action, string controller, object routeValues) 
     { 
      var a = (new UrlHelper(helper.ViewContext.RequestContext)) 
         .Action(action, controller, routeValues); 

      var form = new TagBuilder("form"); 
      form.Attributes.Add("method", "get"); 
      form.Attributes.Add("action", a); 

      var input = new TagBuilder("input"); 
      input.Attributes.Add("type", "submit"); 
      input.Attributes.Add("value", value); 

      form.InnerHtml = input.ToString(TagRenderMode.SelfClosing); 

      return form.ToString(TagRenderMode.Normal); 
     } 
    } 
} 

Además, a diferencia de cdmckay de código, este compilará;) Soy consciente de que puede haber bastante sobrecarga en este código, pero espero que no necesite ejecutarlo muchas veces en cada página. En caso de que lo haga, probablemente haya un montón de optimizaciones que podría hacer.

+0

Aparte no tener las instrucciones de uso, ¿qué impide que compile mi ejemplo? (No lo he probado, solo tengo curiosidad) – cdmckay

+0

Bueno, para empezar, el método Url.Action() no está disponible, excepto en la vista, porque Url es una propiedad de ViewPage/ViewUserControl, que mapas a una instancia de un UrlHelper. En lugar de simplemente hacer referencia a una propiedad que no existe, creo una instancia basada en el RequestContext actual. Ahora veo que ha cambiado su código a "var action = Html.ActionLink (...)", que compilaría si usó "var action = helper.ActionLink (...)", pero le daría el toda la etiqueta , que no desea en la propiedad de acción del formulario ... –

+1

¡Esto no funciona bien si su "ActionButton" ya está dentro de un formulario! –

3

Código de Tomas' respuesta:

public static class HtmlExtensions 
{ 
    public static string ActionButton(this HtmlHelper helper, string value, 
     string action, string controller, object routeValues) 
    { 
    UrlHelper urlHelper = new UrlHelper(helper.ViewContext); 
    var action = urlHelper.Action(action, controller, routeValues); 

    var html = new StringBuilder(); 
    html.AppendFormat("<form method='get' action'{0}'>", action).AppendLine() 
     .AppendFormat(" <input type='submit' value='{0}' />", value).AppendLine() 
     .AppendFormat("</form>").AppendLine(); 

    return html.ToString(); 
    } 
} 
+0

En respuesta a tu edición: no puedes usar Html.ActionLink() - usa helper.ActionLink si quieres eso. Sin embargo, eso producirá una etiqueta ancla completa (y actualmente con una URL incorrecta, ya que el primer parámetro es el texto del enlace y el segundo es el nombre de la acción ...) y eso no es lo que queremos aquí. –

+0

Vaya, tuve Url.Action() antes, luego me lo adiviné. De todos modos, ya está. – cdmckay

+0

También reemplaza la URL con urlHelper. – cdmckay

13

Si quieres que se comporte como un vínculo, pero 'look' como un botón sólo tiene que utilizar el ActionLink con una clase CSS.

<%: Html.ActionLink("Back", "Index", null, new { @class = "link-button" })%> 

Aquí está el CSS de un botón que estoy usando.

.link-button { 
    -moz-border-radius:0.333em 0.333em 0.333em 0.333em; 
    -moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.4); 
    background:-moz-linear-gradient(center top , white, #306AB5 4%, #274976) repeat scroll 0 0 transparent; 
    border-color:#306AB5 #2B5892 #274771; 
    border-style:solid; 
    border-width:1px; 
    color:white; 
    cursor:pointer; 
    display:inline-block; 
    font-size:1.167em; 
    font-weight:bold; 
    line-height:1.429em; 
    padding:0.286em 1em 0.357em; 
    text-shadow:0 1px 2px rgba(0, 0, 0, 0.4); 
} 


.link-button { 
    color: white; 
    border-color: #a1a7ae #909498 #6b7076; 
    background: #9fa7b0 url(../images/old-browsers-bg/button-element-grey-bg.png) repeat-x top; 
    background: -moz-linear-gradient(
     top, 
     white, 
     #c5cbce 5%, 
     #9fa7b0 
    ); 
    background: -webkit-gradient(
     linear, 
     left top, left bottom, 
     from(white), 
     to(#9fa7b0), 
     color-stop(0.05, #c5cbce) 
    ); 
    -moz-text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); 
    -webkit-text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); 
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); 
    -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); 
    -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); 
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); 
    } 
    .link-button:hover { 
     border-color: #a1a7b0 #939798 #6e7275; 
     background: #b1b5ba url(../images/old-browsers-bg/button-element-grey-hover-bg.png) repeat-x top; 
     background: -moz-linear-gradient(
      top, 
      white, 
      #d6dadc 4%, 
      #b1b5ba 
     ); 
     background: -webkit-gradient(
      linear, 
      left top, left bottom, 
      from(white), 
      to(#b1b5ba), 
      color-stop(0.03, #d6dadc) 
     ); 
    } 
    .link-button:active { 
     border-color: #666666 #ffffff #ffffff #979898; 
     background: #dddddd url(../images/old-browsers-bg/button-element-grey-active-bg.png) repeat-x top; 
     background: -moz-linear-gradient(
      top, 
      #f1f1f1, 
      #dddddd 
     ); 
     background: -webkit-gradient(
      linear, 
      left top, left bottom, 
      from(#f1f1f1), 
      to(#dddddd) 
     ); 
    } 
0

he modificado el código Tomas Lyckens para devolver un MvcHtmlString en lugar de sólo una cadena. Esto asegura que la salida sea HTML, no escapada como texto. También lo documenté xml bien. Gracias a Tomas que hizo todo el trabajo real.

/// <summary> 
    /// Returns an HTML submit button (enclosed in its own form) that contains the virtual path of the specified action. 
    /// </summary> 
    /// <param name="helper">The HTML helper instance that this method extends.</param> 
    /// <param name="buttonText">The visible text of the button.</param> 
    /// <param name="action">The name of the action.</param> 
    /// <param name="controller">The name of the controller.</param> 
    /// <param name="routeValues">An object that contains the parameters for a route. The parameters are retrieved through reflection by examining the properties of the object. The object is typically created by using object initializer syntax.</param> 
    /// <returns></returns> 
    public static MvcHtmlString ActionButton(this HtmlHelper helper, string buttonText, string action, string controller, object routeValues) 
    { 
     string a = (new UrlHelper(helper.ViewContext.RequestContext)).Action(action, controller, routeValues); 

     var form = new TagBuilder("form"); 
     form.Attributes.Add("method", "get"); 
     form.Attributes.Add("action", a); 

     var input = new TagBuilder("input"); 
     input.Attributes.Add("type", "submit"); 
     input.Attributes.Add("value", buttonText); 

     form.InnerHtml = input.ToString(TagRenderMode.SelfClosing); 

     return MvcHtmlString.Create(form.ToString(TagRenderMode.Normal)); 
    } 
6

Dos versiones para hacer una extensión para ...

<button 
    onclick="javascript:window.location=('@Url.Action("Review", "Order", null)')" 
    >Review Order</button> 

versión discreta:

<button data-action="@Url.Action("Review", "Order", null)">Review Order</button> 

$(document).on('click', "[data-action]", 
    function(e) { window.location = $(this).attr('data-action'); } 
); 

Si hay usuarios que no tiene activado Javascript, a continuación, formar la etiqueta es el camino a seguir. Aunque, esto hace que la situación sea difícil si su enlace ya está dentro de un formulario. Sin embargo, puede cambiar la acción y el método para OBTENER.

0

Aquí hay una versión de VB.NET con algo más, los parámetros del controlador y de las rutas son opcionales, por lo que se pueden usar sin repetir el nombre del controlador si es igual al controlador actual/predeterminado de la página.

Public Module MvcExtensions 

    ''' <summary> 
    ''' Returns an HTML submit button (enclosed in its own form) that contains the virtual path of the specified action. 
    ''' </summary> 
    ''' <param name="helper">The HTML helper instance that this method extends.</param> 
    ''' <param name="text">Text displayed in the button.</param> 
    ''' <param name="action">Action name.</param> 
    ''' <param name="controller">Optional controller name, using current when null.</param> 
    ''' <param name="routeValues"> 
    ''' An object that contains the parameters for a route. The parameters are retrieved 
    ''' through reflection by examining the properties of the object. 
    ''' The object is typically created by using object initializer syntax. 
    ''' </param> 
    ''' <returns> 
    ''' HTML output. 
    ''' </returns> 
    <Extension()> _ 
    Public Function ActionButton(helper As HtmlHelper, text As String, action As String, 
           Optional controller As String = Nothing, Optional routeValues As Object = Nothing) As MvcHtmlString 

     ' Validate parameters 
     If String.IsNullOrEmpty(text) Then Throw New ArgumentNullException("text") 

     ' Get post back URL for action 
     Dim actionUrl As String = New UrlHelper(helper.ViewContext.RequestContext).Action(action, controller, routeValues) 

     ' Build form tag with action URL 
     Dim form = New TagBuilder("form") 
     form.Attributes.Add("method", "get") 
     form.Attributes.Add("action", actionUrl) 

     ' Add button 
     Dim input = New TagBuilder("input") 
     input.Attributes.Add("type", "submit") 
     input.Attributes.Add("value", text) 
     form.InnerHtml = input.ToString(TagRenderMode.SelfClosing) 

     ' Return result as HTML 
     Return MvcHtmlString.Create(form.ToString(TagRenderMode.Normal)) 

    End Function 

End Module 

Luego se puede invocar como los otros controles MVC, con un código mínimo en la página.

Esto realmente debería haber entrado en el marco de MVC de la base desde el principio; parece un requisito tan obvio.Creo que los botones son mucho más intuitivos para el usuario al realizar acciones que crean o cambian cosas, en lugar de enlaces. Los enlaces deberían navegar hacia la información relacionada (no cambiar nada). Si tuviera una grilla, usaría ActionLink para cualquier navegación de datos (por ejemplo, haga clic en el nombre de un producto para ir a la página del producto), pero solo ActionButton para "acciones" reales, como editar y eliminar.

0

Si desea un botón que funciona como un enlace esto debería funcionar:

<input type="button" value="Button Text" 
    onclick="@("location.href='http://stackoverflow.com/q/901372/2460971'")" /> 

Si desea que el botón para utilizar una acción de controlador sólo es necesario un cambio menor:

<input type="button" value="Button Text" 
    onclick="@("location.href='" + Url.Action("ActionName", "ControllerName") + "'")" />