jquery $ .ajax publica varias veces (una extra después de cada envío posterior)

En mi formulario de contraseña olvidada, la publicación jquery ajax se activa varias veces (una más después de cada envío). Entonces, si el usuario ingresa un correo electrónico no válido 3 veces, y luego un correo electrónico válido, el usuario recibe 4 correos electrónicos con contraseña cambiada. Parece que el evento se astack cada vez que se produce un error, y todos se activan en el siguiente envío. Aquí está todo mi código relevante. ¿Qué estoy haciendo mal?

JS

RetrievePassword = function () { var $popup = $("#fancybox-outer"); var form = $popup.find("form"); form.submit(function (e) { var data = form.serialize(); var url = form.attr('action'); $.ajax({ type: "POST", url: url, data: data, dataType: "json", success: function (response) { ShowMessageBar(response.Message); $.fancybox.close() }, error: function (xhr, status, error) { ShowMessageBar(xhr.statusText); } }); return false; }); }; 

CONTROLADOR MVC / ACCION

 [HandlerErrorWithAjaxFilter, HttpPost] public ActionResult RetrievePassword(string email) { User user = _userRepository.GetByEmail(email); if (user == null) throw new ClientException("The email you entered does not exist in our system. Please enter the email address you used to sign up."); string randomString = SecurityHelper.GenerateRandomString(); user.Password = SecurityHelper.GetMD5Bytes(randomString); _userRepository.Save(); EmailHelper.SendPasswordByEmail(randomString); if (Request.IsAjaxRequest()) return Json(new JsonAuth { Success = true, Message = "Your password was reset successfully. We've emailed you your new password.", ReturnUrl = "/Home/" }); else return View(); } 

HandlerErrorWithAjaxFilter

 public class HandleErrorWithAjaxFilter : HandleErrorAttribute { public bool ShowStackTraceIfNotDebug { get; set; } public string ErrorMessage { get; set; } public override void OnException(ExceptionContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { var content = ShowStackTraceIfNotDebug || filterContext.HttpContext.IsDebuggingEnabled ? filterContext.Exception.StackTrace : string.Empty; filterContext.Result = new ContentResult { ContentType = "text/plain", Content = content }; string message = string.Empty; if (!filterContext.Controller.ViewData.ModelState.IsValid) message = GetModeStateErrorMessage(filterContext); else if (filterContext.Exception is ClientException) message = filterContext.Exception.Message.Replace("\r", " ").Replace("\n", " "); else if (!string.IsNullOrEmpty(ErrorMessage)) message = ErrorMessage; else message = "An error occured while attemting to perform the last action. Sorry for the inconvenience."; filterContext.HttpContext.Response.Status = "500 " + message; filterContext.ExceptionHandled = true; filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; } else { base.OnException(filterContext); } } private string GetModeStateErrorMessage(ExceptionContext filterContext) { string errorMessage = string.Empty; foreach (var key in filterContext.Controller.ViewData.ModelState.Keys) { var error = filterContext.Controller.ViewData.ModelState[key].Errors.FirstOrDefault(); if (error != null) { if (string.IsNullOrEmpty(errorMessage)) errorMessage = error.ErrorMessage; else errorMessage = string.Format("{0}, {1}", errorMessage, error.ErrorMessage); } } return errorMessage; } } 

Aquí hay más JS. Estoy usando el plugin de fancybox como mi lightbox. El enlace Recuperar contraseña está en la caja de luz de inicio de sesión.

 $(document).ready(function () { $(".login").fancybox({ 'hideOnContentClick': false, 'titleShow': false, 'onComplete': function () { $("#signup").fancybox({ 'hideOnContentClick': false, 'titleShow':false, 'onComplete': function () { } }); $("#retrievepassword").fancybox({ 'hideOnContentClick': false, 'titleShow': false, 'onComplete': function () { } }); } }); }); 

No soy un experto en jQuery, pero me parece que cada vez que fancybox onComplete se activa, se agrega (otro) controlador de eventos a #retrievepassword y #signup … Me estoy perdiendo el rest del html en la página, así que no sé si / cuando se carga el contenido del diálogo de inicio de sesión, pero lo siguiente podría funcionar mejor:

 $(document).ready(function () { $(".login").fancybox({ 'hideOnContentClick': false, 'titleShow': false, 'onComplete': function () { } }); $("#signup").fancybox({ 'hideOnContentClick': false, 'titleShow':false, 'onComplete': function () { } }); $("#retrievepassword").fancybox({ 'hideOnContentClick': false, 'titleShow': false, 'onComplete': function () { } }); });