asp.net mvc - son - MVC 3: Agregar condicionalmente el atributo deshabilitado con los HtmlHelpers
que son los helpers en mvc (6)
¿Qué piensas de mi solución simple ? Funciona fácilmente con ambos tipos posibles de HtmlAttributes
:
-
Dictionary<string, object>
-
Anonymous Object
:
Primero agregue la siguiente extension class
simple a su proyecto:
public static class HtmlAttributesExtensions
{
public static IDictionary<string, object> AddHtmlAttrItem(this object obj, string name, object value, bool condition)
{
var items= !condition ? new RouteValueDictionary(obj) : new RouteValueDictionary(obj) {{name, value}};
return UnderlineToDashInDictionaryKeys(items);
}
public static IDictionary<string, object> AddHtmlAttrItem(this IDictionary<string, object> dictSource, string name, object value, bool condition)
{
if (!condition)
return dictSource;
dictSource.Add(name, value);
return UnderlineToDashInDictionaryKeys(dictSource);
}
private static IDictionary<string, object> UnderlineToDashInDictionaryKeys(IDictionary<string,object> items)
{
var newItems = new RouteValueDictionary();
foreach (var item in items)
{
newItems.Add(item.Key.Replace("_", "-"), item.Value);
}
return newItems;
}
}
Ahora en Vista:
Ejemplo1 ( HtmlAttributes
tipo como Anonymous Object
)
@{
var hasDisabled=true;
}
@Html.CheckBox("CheckBox1"
, true
, new { @class = "Class1"}
.AddHtmlAttrItem("disabled", "disabled", hasDisabled))
.
Ejemplo 2 ( HtmlAttributes
tipo como Dictionary<string, object>
)
@Html.CheckBox("CheckBox1"
, true
, new Dictionary<string, object> { { "class", "Class1" }
.AddHtmlAttrItem("disabled", "disabled", hasDisabled))
.
¡Ahora simplemente cambie el valor de
hasDisabled
atrue
ofalse
!
Ejemplo 3 (múltiples propiedades condicionales)
@{
var hasDisabled=true;
var hasMax=false ;
var hasMin=true ;
}
@Html.CheckBox("CheckBox1"
, true
, new { @class = "Class1"}
.AddHtmlAttrItem("disabled", "disabled", hasDisabled)
.AddHtmlAttrItem("data-max", "100", hasMax)
.AddHtmlAttrItem("data-min", "50", hasMin))
.
Tengo una aplicación web ASP.Net MVC 3 y estoy agregando una casilla de verificación a una página de vista usando la clase HtmlHelper, así ...
@Html.CheckBox("CheckBox1", true, new { @class = "Class1" })
Lo que quiero hacer es agregar de manera condicional el atributo deshabilitado en función de una propiedad de estado de vista. Básicamente, lo siguiente sería ideal ...
@Html.CheckBox("CheckBox1", true, new { @class = "Class1", @disabled = Model.ReadOnly })
Desafortunadamente, debido a la naturaleza del atributo desactivado, esto no funcionará porque cualquier valor asignado al atributo desactivado (incluso "falso") se traducirá como verdadero.
Ya he pensado en algunas soluciones para solucionar este problema, por lo que la pregunta no es cómo puedo hacerlo. Pero mejor dicho, ¿hay una manera simple como el método deseado arriba? o tengo que recurrir a uno de los siguientes? ..
Lo que sé que podría hacer ...
Cree una instrucción if / else y escriba en diferentes líneas
Html.CheckBox
(no es excelente para la legibilidad, y es posible con lanzar una advertencia de marcado, no estoy seguro)Saltee la clase HtmlHelper y escriba a mano la etiqueta que permite mejores atributos condicionalmente (mantiene el código más corto, pero agrega inconsistencia)
Cree un asistente personalizado que tome un parámetro "deshabilitado" (la solución más limpia, pero que requiere métodos adicionales no deseados, probablemente la mejor opción hasta el momento)
Aquí está mi respuesta de esta pregunta similar: https://.com/a/13922813/495000
Creé el siguiente Ayudante: requiere un booleano y un objeto anónimo. Si la opción deshabilitada es verdadera, agrega el atributo deshabilitado al objeto anónimo (que en realidad es un diccionario) con el valor "deshabilitado", de lo contrario no agrega la propiedad en absoluto.
public static RouteValueDictionary ConditionalDisable(
bool disabled,
object htmlAttributes = null)
{
var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (disabled)
dictionary.Add("disabled", "disabled");
return dictionary;
}
Un ejemplo de ello en acción:
@Html.TextBoxFor(m => m.SomeProperty,
HtmlHelpers.ConditionalDisable(true, new { @class = "someClass"))
Una gran ventaja de este enfoque para mí fue que funciona con prácticamente todos los MVC HtmlHelpers, ya que todos tienen Sobrecargas que aceptan un RouteValueDictionary en lugar de un objeto anónimo.
Advertencias :
HtmlHelper.AnonymousObjectToHtmlAttributes()
usa algún código de ninja para hacer las cosas. No estoy del todo seguro de cuán eficiente es ... pero ha sido suficiente para lo que lo uso. Su experiencia puede ser diferente.
No me gusta especialmente el nombre, pero no pude encontrar nada mejor. Renombrar es fácil.
Tampoco me gusta la sintaxis de uso, pero de nuevo no pude encontrar nada mejor. No debería ser difícil cambiar. Un método de extensión en el objeto es una idea ... terminarías con new { @class = "someClass" }.ConditionalDisable(true)
pero luego si solo quieres el atributo de deshabilitar y no tienes nada adicional para agregarte terminar con algo bruto como new {}.ConditionalDisable(true);
y también terminas con un método de extensión que aparece para todos los object
... que probablemente no sea deseable.
Defina esto en algún lugar de su vista / ayudantes
@functions {
object getHtmlAttributes (bool ReadOnly, string CssClass)
{
if (ReadOnly) {
return new { @class = CssClass, @readonly = "readonly" };
}
return new { @class = CssClass };
}
}
Luego usa:
@Html.TextBox("name", "value", @getHtmlAttributes(Model.ReadOnly, "test"))
Realizar la adición del lado del cliente del atributo desactivado funciona para mí. Tenga en cuenta que debe verificar qué campos se pueden editar desde el lado del servidor, pero esto también se aplica a los casos en que el atributo deshabilitado también se declara decorativamente.
En este ejemplo he desactivado todos los childeren de un formulario usando jQuery.
if (Model.CanEdit)
{
<script type="text/javascript">
$(document).ready(function() {
$(''#editForm *'').attr(''disabled'', true);
});
</script>
}
Si desea una sintaxis más precisa sin necesidad de una función auxiliar, podría utilizar una declaración ternaria al definir el diccionario utilizado para los atributos html del asistente @ HTML.Checkbox ...
@Html.CheckBox("CheckBox1", true, Model.ReadOnly
? new { @class = "Class1", @disabled = Model.ReadOnly }
: null)
En este caso es Model.ReadOnly es falso, null se pasa como el diccionario de atributos html.
@Html.TextBoxFor(m => m.FieldName, Html.FixBoolAttributes(new {
@class = "myClass",
@readonly = myFlag
}))
public static class BooleanAttributeFix
{
/// <summary>
/// Normalises HTML boolean attributes so that readonly=true becomes readonly="readonly" and
/// readonly=false removes the attribute completely.
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static RouteValueDictionary FixBoolAttributes(this HtmlHelper htmlHelper, object htmlAttributes)
{
var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
foreach(var attrName in new[] { "disabled", "readonly" })
{
object value;
if(attrs.TryGetValue(attrName, out value))
{
if(isTruthy(value))
{
// Change from readonly="true" to readonly="readonly"
attrs[attrName] = attrName;
}
else
{
// Remove attribute entirely
attrs.Remove(attrName);
}
}
}
return attrs;
}
/// <summary>
/// Apply similar loose rules like javascript does for whether a value is true or not.
/// e.g. 1 = true, non-empty string = true and so on.
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
private static bool isTruthy(object val)
{
if(val == null)
return false;
if(val is string)
{
return !String.IsNullOrEmpty((string)val);
}
Type t = val.GetType();
if(t.IsValueType && Nullable.GetUnderlyingType(t) == null)
{
// If a non-nullable value type such as int we want to check for the
// default value e.g. 0.
object defaultValue = Activator.CreateInstance(t);
// Use .Equals to compare the values rather than == as we want to compare
// the values rather than the boxing objects.
// See http://.com/questions/6205029/comparing-boxed-value-types
return !val.Equals(defaultValue);
}
return true;
}
}