2016-04-17 5 views
0

J'ai utilisé l'approche de Darin-Dimitrov pour créer un formulaire de registre à plusieurs étapes qui est expliqué Here et fonctionne correctement. Maintenant, je veux gérer les événements de soumission pour les boutons Précédent, Suivant et Terminer en utilisant jquery ajax au lieu de Html.Beginform().Implémentation de Jquery Ajax dans des formulaires de registre multi-étapes basés sur des modèles de vue éclatés dans ASP.NET MVC5

Notes:

  • J'utilise MVC 5 avec .NET 4.5.2
  • J'ai fileUpload et les propriétés datetime dans mon deuxième viewmodel étape.

Voici mon viewmodel

[Serializable] 
public class RegisterWizardViewModel 
{ 


    public int CurrentStepIndex { get; set; } 
    public IList<IStepViewModel> Steps { get; set; } 

    public void Initialize() 
    { 
     Steps = typeof(IStepViewModel) 
      .Assembly 
      .GetTypes() 
      .Where(t => !t.IsAbstract && typeof(IStepViewModel).IsAssignableFrom(t)) 
      .Select(t => (IStepViewModel)Activator.CreateInstance(t)) 
      .ToList(); 
    } 

    public interface IStepViewModel 
    { 

    } 

    [Serializable] 
    public class RegisterStep1ViewModel : IStepViewModel 
    { 
     [Required] 
     [EmailAddress] 
     public string Email { get; set; } 

     [Required] 
     [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 
     [DataType(DataType.Password)] 
     public string Password { get; set; } 

     [DataType(DataType.Password)] 
     [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 
     public string ConfirmPassword { get; set; } 

    } 

    [Serializable] 
    public class RegisterStep2ViewModel : IStepViewModel 
    { 

     [Display(Name = "FirstName", ResourceType = typeof(Resources.Resources))] 
     public string FirstName { get; set; } 

     [Display(Name = "LastName", ResourceType = typeof(Resources.Resources))] 
     public string LastName { get; set; } 

     [NonSerialized] 
     private HttpPostedFileBase _file; 
     public HttpPostedFileBase File 
     { 
      get 
      { 
       return _file; 
      } 
      set 
      { 
       _file = value; 
      } 
     } 

     [Display(Name = "BirthDay", ResourceType = typeof(Resources.Resources))] 
     [DataType(DataType.Date)] 
     [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}", ApplyFormatInEditMode = true)] 
     public DateTime? BirthDay { get; set; } 

     [Display(Name = "NationalCode", ResourceType = typeof(Resources.Resources))] 
     public int NationalCode { get; set; } 

     [Display(Name = "Gender", ResourceType = typeof(Resources.Resources))] 
     public bool IsMale { get; set; } 

     [Display(Name = "Mobile", ResourceType = typeof(Resources.Resources))] 
     public string MobilePhone { get; set; } 

     [Display(Name = "Country", ResourceType = typeof(Resources.Resources))] 
     public string Country { get; set; } 

     [Display(Name = "Address", ResourceType = typeof(Resources.Resources))] 
     public string Address { get; set; } 

     [MustBeTrue] 
     public bool CaptchaValid { get; set; } 
    } 

} 

Voici mon contrôleur

[AllowAnonymous] 
    public ActionResult Index() 
    { 
     var wizard = new RegisterWizardViewModel(); 
     wizard.Initialize(); 
     return View(wizard); 
    } 

    [HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public ActionResult Index([Deserialize] RegisterWizardViewModel wizard, RegisterWizardViewModel.IStepViewModel step) 
    { 


     wizard.Steps[wizard.CurrentStepIndex] = step; 

     if (ModelState.IsValid) 
     { 
      if (!string.IsNullOrEmpty(Request["next"])) 
      { 
       wizard.CurrentStepIndex++; 

      } 
      else if (!string.IsNullOrEmpty(Request["prev"])) 
      { 
       wizard.CurrentStepIndex--; 
      } 
      else 
      { 

       var model1 = wizard.Steps[0] as RegisterWizardViewModel.RegisterStep1ViewModel; 
       var model2 = wizard.Steps[1] as RegisterWizardViewModel.RegisterStep2ViewModel; 


       var uploadedFile = (model2.File != null && model2.File.ContentLength > 0) ? new byte[model2.File.InputStream.Length] : null; 
       if (uploadedFile != null) 
       { 
        model2.File.InputStream.Read(uploadedFile, 0, uploadedFile.Length); 
       } 

       var user = new ApplicationUser { UserName = model1.Email, Email = model1.Email, FirstName = model2.FirstName, LastName = model2.LastName, Image = uploadedFile , BirthDay = model2.BirthDay, IsMale = model2.IsMale, NationalCode = model2.NationalCode, MobilePhone = model2.MobilePhone, Country = model2.Country, Address = model2.Address }; 
       var result = UserManager.Create(user, model1.Password); 
       if (result.Succeeded) 
       { 
        SignInManager.SignIn(user, isPersistent: false, rememberBrowser: false); 

        return Json(new { response = "Redirect", url = Url.Action("Index", "Home") }); 
       } 
       else 
       { 
        AddErrors(result); 
       } 

      } 

     } 
     else if (!string.IsNullOrEmpty(Request["prev"])) 
     { 
      wizard.CurrentStepIndex--; 
     } 

     return View(wizard); 
    } 

Et je l'ai utilisé ce code jquery pour soumettre via un appel ajax dans mon index des registerwizard.

@section scripts{ 
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script> 
<script type="text/javascript"> 
    $(function() { 
     $('form').on("submit", function (e) { 
      e.preventDefault; 
      if ($(this).valid()) { 
       $.ajax({ 
        url: this.action, 
        type: this.method, 
        data: $(this).serialize(), 
        success: function (result) { 
         window.location = result.url; 
        } 
       }); 
      } 
      return false; 
     }); 
    }); 

</script> 

} 

Eh bien maintenant, le problème est le contrôleur ne marche pas reconnaître que le bouton a été pressé et Request["next"] ou Request["prev"] revenir toujours nul et en cas d'état de modèle étant valable pour la première étape (e-mail, passer, confirmpass), le contrôleur va directement à créer un utilisateur. il vaut la peine de mentionner que puisque je ne pouvais pas arriver à la deuxième étape via l'appel ajax je ne sais pas si le téléchargement de fichiers et la propriété datetime envoyé au contrôleur sans aucun problème ou non.
Mise à jour:
est ici Index Voir

@using (Html.BeginForm("Index", "RegisterWizard", FormMethod.Post, new { @class = "form-horizontal", role = "form", enctype = "multipart/form-data" })) 
    { 
     @Html.AntiForgeryToken() 

     @Html.Serialize("wizard", Model) 

     @Html.Hidden("StepType", Model.Steps[Model.CurrentStepIndex].GetType()) 
     @Html.EditorFor(x => currentStep, null, "") 


     if (Model.CurrentStepIndex > 0) 
     { 
      <div class="col-xs-9 col-sm-6 col-md-5 col-lg-5" style="padding-right:0px;"> 
       <input type="submit" class="btn btn-default" value="Previous" name="prev" /> 

      </div> 


     } 

     if (Model.CurrentStepIndex < Model.Steps.Count - 1) 
     { 
      <div class="col-xs-10 col-sm-8 col-md-6" style=""> 
       <input type="submit" class="btn btn-default" value="Next" name="next" style="float:left;"/> 

      </div> 


     } 
     else 
     { 
      <div class="col-xs-3 col-sm-6 col-md-7 col-lg-7" style="padding-right:0px;"> 

       <input type="submit" class="btn btn-default " value="Finish" name="finish" /> 

      </div> 


     } 
    } 
+0

Vous pouvez utiliser @ Ajax.BeginForm –

+0

@BonMacalindong merci pour votre suggestion mais compte tenu du contrôle total sur l'appel Ajax je préfère utiliser jquery Ajax –

Répondre

0

Eh bien, dans le cas d'une personne face à ce problème et a probablement le même problème j'expliquer ma solution de contournement.
problème principal reconnaissant quel bouton a été envoyé le formulaire:
J'ai ajouté une entrée cachée nommée Button et changé son nom dynamiquement via jquery sur l'événement click sur chaque bouton et finalement modifié mon contrôleur pour obtenir cette valeur de la demande.
les suivants sont des vues partielles qui conservent la forme entière et post-action de mon contrôleur.

@using Microsoft.Web.Mvc 
@model Models.RegisterWizardViewModel 

@{ 
    var currentStep = Model.Steps[Model.CurrentStepIndex]; 
} 

@using (Html.BeginForm("Index", "RegisterWizard", FormMethod.Post, new { @class = "form-horizontal", role = "form", enctype = "multipart/form-data", @id = "mainRWF" })) 
{ 
    @Html.AntiForgeryToken() 
    @Html.Hidden("Button") 
    @Html.Serialize("wizard", Model) 
    @Html.Hidden("StepType", Model.Steps[Model.CurrentStepIndex].GetType()) 
    @Html.EditorFor(x => currentStep, null, "") 

    if (Model.CurrentStepIndex > 0) 
     { 
      <div > 
       <input type="submit" value="Previous" name="prev" /> 
      </div> 
     } 

    if (Model.CurrentStepIndex < Model.Steps.Count - 1) 
     { 
      <div > 
      <input type="submit" value="Next" name="next" /> 
      </div> 
     } 
    else 
     { 
      <div > 
      <input type="submit" value="Submit" name="finish"/> 
      </div> 
     } 
} 

...

[ValidateAntiForgeryToken] 
    public async Task<ActionResult> Index([Deserialize]RegisterWizardViewModel wizard, RegisterWizardViewModel.IStepViewModel step) 
    { 
     wizard.Steps[wizard.CurrentStepIndex] = step; 

     if (ModelState.IsValid) 
     { 
      if (Request.Form.GetValues("Button").Contains("next")) 
      { 
       wizard.CurrentStepIndex++; 

      } 
      else if (Request.Form.GetValues("Button").Contains("prev")) 
      { 
       wizard.CurrentStepIndex--; 
      } 
      else 
      { 
       //Do stuff with received values 
       return Json(new { response = "Success" }); 

      } 

     } 
     else if (Request.Form.GetValues("Button").Contains("prev")) 
     { 
      // Even if validation failed we allow the user to 
      // navigate to previous steps 
      wizard.CurrentStepIndex--; 
     } 
     else if (!ModelState.IsValid) 
     { 
      // If we got this far, something failed, redisplay form with errors by inserting this into html() of success func of ajax 
      return PartialView("_IndexPartial", wizard); 
     } 

    // return next step 
    return PartialView("_IndexPartial", wizard); 

} 

et, évidemment, j'ai eu des problèmes avec le fichier télécharger! et a choisi html5 formData pour gérer le téléchargement en tant qu'option de données de l'appel ajax pour terminer le bouton.
je voudrais appriciate commentaires sur cette solution afin de le rendre meilleur.