tutorial net mvc formulario form asp c# javascript asp.net-mvc validation

c# - formulario - razor form asp net mvc



¿Cómo proporcionar advertencias durante la validación en ASP.NET MVC? (5)

A veces, la entrada del usuario no es estrictamente inválida, pero puede considerarse problemática.

Por ejemplo:

  • Un usuario ingresa una oración larga en un campo Name una sola línea. Probablemente debería haber usado el campo Description lugar .
  • Un usuario ingresa un Name que es muy similar al de una entidad existente. Tal vez está ingresando la misma entidad pero no se dio cuenta de que ya existe, o algún usuario concurrente acaba de ingresar.

Algunos de estos pueden revisarse fácilmente desde el lado del cliente, otros requieren verificaciones del lado del servidor.

¿Cuál es la mejor manera , tal vez algo similar a la validación de DataAnnotations , para proporcionar advertencias al usuario en tales casos? La clave aquí es que el usuario debe poder anular la advertencia y aún así enviar el formulario (o volver a enviar el formulario, dependiendo de la implementación).

La solución más viable que se le viene a la mente es crear algún atributo, similar a CustomValidationAttribute , que pueda hacer una llamada AJAX y que muestre algún texto de advertencia, pero que no afecte al ModelState . El uso previsto es este:

[WarningOnFieldLength(MaxLength = 150)] [WarningOnPossibleDuplicate()] public string Name { get; set; }

En la vista:

@Html.EditorFor(model => model.Name) @Html.WarningMessageFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name)

Entonces, ¿alguna idea?


Aquí hay una forma de hacer una advertencia sin escribir ningún código del lado del servidor. Agregue la clase "ignorar-validación" a los elementos inválidos deseados en el envío de formulario, y en su método de validación personalizado devuelva "verdadero" si el elemento tiene esta clase (si tiene la clase, significa que el formulario se envió una vez). También necesitarás eliminar la clase "ignorar-validar" de #IdOfInput en desenfoque o cambio, dependiendo del tipo de control que sea, ese bit de código no se representa aquí:

<script type="text/javascript"> $.validator.addMethod(''isValidCustomMethod'', function (value, element) { if($(element).hasClass(''ignore-validation'')){ return true; } var isValid = false; //your code to do validation would actually go here return isValid; }); $(document).ready(function () { $(''#IdOfInput'').rules(''add'', { isValidCustomMethod: true, messages: { isValidCustomMethod: ''Your warning message here''} }); $(''form'').submit(function () { $(this).validate().invalidElements().each(function () { if($(this).attr(''id'')==''IdOfInput''){ $(this).addClass(''ignore-validation''); } }); }); }); </script>


Esto es solo un boceto de una posible solución. Hay muchos ejemplos de cómo agregar atributos personalizados (incluido el anterior), así que omitiré ese bit.

Es posible agregar el uso de ignorar en la función del validador jQuery .

Entonces usa

$("form").validate({ ignore: ".warning-only" });

y use el validador del lado del cliente para agregar la clase ''solo advertencia'' después de una primera pasada a través del validador. Esto debería permitir que el formulario se envíe al servidor.

Como digo, solo un boceto, pero es algo que he estado investigando para su uso posterior.


Puede usar la función de los valores de la validación de jquery para simplificar su vida.

Ex.

@Html.LabelFor(m => m.UserName) @Html.TextBoxFor(m => m.UserName) @Html.ValidationMessageFor(m => m.UserName) <label>Ignore Warnings</label> <input id="ignore-warnings" type="checkbox" /> <script> $(function () { $("#UserName").rules("add", { minlength: { param: 6, depends: function (element) { return !$("#ignore-warnings").attr(''checked''); } }, // server side remote validation for duplicate check remote: { param: ''/account/duplicate'', depends: function (element) { return !$("#ignore-warnings").attr(''checked''); } } }); }); </script>


Solo un comentario rápido sobre la posible implementación de reenviar que mencionó ...

Para el "¿quisiste hacer esto?" tipo de validación, desde la perspectiva de un usuario, tener que volver a enviar un formulario basado en la suposición de que cometieron un error podría ser muy molesto. Solo implementaría esta ''pseudovalidación'' en el lado del cliente con javascript y (con suerte, rápido) llamadas ajax si tiene que golpear el servidor.

También intentaré mostrar las advertencias en los eventos de desenfoque / cambio de la entrada para que se muestren antes de que el usuario acceda a enviar. Tal vez no sea práctico en todas las situaciones, pero pensé que lo tiraría allí.


Diseño general

Para empezar, creo que tendrías que rastrear de alguna manera si el usuario elige ignorar las advertencias. Una forma simple y transparente de hacerlo es tener una casilla de verificación Ignorar advertencias , que el usuario debería verificar antes de enviarla. Otra opción es hacerles enviar el formulario dos veces e ignorar las advertencias en el segundo envío; entonces probablemente necesitarías un campo oculto Ignorar Advertencias . Podría haber otros diseños, pero en aras de la simplicidad iré con la primera opción.

En resumen, el enfoque es crear

  • Un atributo de anotación de datos personalizado para todos los modelos de vista que admiten el tipo de advertencia de validación;
  • Una clase base conocida de la que heredarán los modelos de vista;
  • Tendremos que duplicar la lógica en JavaScript para cada atributo personalizado.

Tenga en cuenta que el siguiente código simplemente ilustra el enfoque y tengo que asumir muchas cosas sin conocer el contexto completo.

Ver modelo

En este escenario, es mejor separar un modelo de vista de un modelo real, que es una buena idea de todos modos. Un posible enfoque es tener una clase base para todos los modelos de vista que admiten advertencias:

public abstract class BaseViewModel { public bool IgnoreWarnings { get; set; } }

La razón clave por la que un modelo debe estar separado es que tiene poco sentido almacenar la propiedad IgnoreWarnings en su base de datos.

Su modelo de vista derivado tendrá el siguiente aspecto:

public class YourViewModel : BaseViewModel { [Required] [StringLengthWarning(MaximumLength = 5, ErrorMessage = "Your Warning Message")] public string YourProperty { get; set; } }

StringLengthWarning es un atributo de anotación de datos personalizado para la validación del servidor y del lado del cliente. Solo admite la longitud máxima y puede ampliarse fácilmente con cualquier otra propiedad necesaria.

Atributo de anotación de datos

El núcleo del atributo es IsValid(value, validationContext method.

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] public class StringLengthWarningAttribute : ValidationAttribute, IClientValidatable { public int MaximumLength { get; set; } public override bool IsValid(object value) { return true; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var model = validationContext.ObjectInstance as BaseViewModel; var str = value as string; if (!model.IgnoreWarnings && (string.IsNullOrWhiteSpace(str) || str.Length > MaximumLength)) return new ValidationResult(ErrorMessage); return base.IsValid(value, validationContext); } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { yield return new StringLengthWarningValidationRule(MaximumLength, ErrorMessage); } }

El atributo implementa IClientValidatable y utiliza una regla de validación de cliente personalizada:

public class StringLengthWarningValidationRule : ModelClientValidationRule { public StringLengthWarningValidationRule(int maximumLength, string errorMessage) { ErrorMessage = errorMessage; ValidationType = "stringlengthwarning"; ValidationParameters.Add("maximumlength", maximumLength); ValidationParameters.Add("ignorewarningsfield", "IgnoreWarnings"); } }

JavaScript del lado del cliente

Finalmente, para que funcione, necesitará el siguiente JavaScript al que se hace referencia desde su vista:

$(function () { $.validator.addMethod(''stringlengthwarning'', function (value, element, params) { var maximumlength = params[''maximumlength'']; var ignorewarningsfield = params[''ignorewarningsfield'']; var ctl = $("#" + ignorewarningsfield); if (ctl == null || ctl.is('':checked'')) return true; return value.length <= maximumlength; }); $.validator.unobtrusive.adapters.add("stringlengthwarning", ["maximumlength", "ignorewarningsfield"], function (options) { var value = { maximumlength: options.params.maximumlength, ignorewarningsfield: options.params.ignorewarningsfield }; options.rules["stringlengthwarning"] = value; if (options.message) { options.messages["stringlengthwarning"] = options.message; } }); }(jQuery));

El JavaScript hace algunas suposiciones que podría querer volver a visitar (el nombre del casillero, etc.).

ACTUALIZACIÓN: HTML Helpers

Para mostrar los mensajes de validación por separado para errores y advertencias, será necesario un par de ayudantes. La siguiente clase proporciona una muestra:

public static class MessageHelpers { public static MvcHtmlString WarningMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] != null) return htmlHelper.ValidationMessageFor(expression); return MvcHtmlString.Empty; } public static MvcHtmlString ErrorMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] == null) return htmlHelper.ValidationMessageFor(expression); return MvcHtmlString.Empty; } }

En la vista, se pueden usar como de costumbre:

@Html.EditorFor(model => model.YourProperty) @Html.ErrorMessageFor(model => model.YourProperty) @Html.WarningMessageFor(model => model.YourProperty)