根据ASP.NET MVC5 splited的ViewModels在多级寄存器形式实现jQuery的阿贾克斯 [英] Implementing Jquery Ajax in Multi-step register forms based on splited viewmodels in ASP.NET MVC5

查看:222
本文介绍了根据ASP.NET MVC5 splited的ViewModels在多级寄存器形式实现jQuery的阿贾克斯的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用达林 - 季米特洛夫的做法作出这说明一个多步骤的登记表<一个href=\"http://stackoverflow.com/questions/6402628/multi-step-registration-process-issues-in-asp-net-mvc-splitted-viewmodels-sing\">Here并能正常工作。
现在我想办理提交previous,使用jQuery阿贾克斯,而不是Html.Beginform()。Next和Finish按钮事件

注:


  • 我使用MVC 5使用.NET 4.5.2

  • 我的FileUpload和我的第二个步骤视图模型日期时间属性。

下面是我的视图模型

  [Serializable接口]
公共类RegisterWizardViewModel
{
    公众诠释CurrentStepIndex {搞定;组; }
    公众的IList&LT; IStepViewModel&GT;步骤{搞定;组; }    公共无效初始化()
    {
        步骤= typeof运算(IStepViewModel)
            。部件
            .GetTypes()
            。凡(T =&GT;!t.IsAbstract和放大器;&安培; typeof运算(IStepViewModel).IsAssignableFrom(T))
            。选择(T =&GT;(IStepViewModel)Activator.CreateInstance(T))
            .ToList();
    }    公共接口IStepViewModel
    {    }    [Serializable接口]
    公共类RegisterStep1ViewModel:IStepViewModel
    {
        [需要]
        [电子邮件地址]
        公共字符串电子邮件{获得;组; }        [需要]
        [StringLength(100,的ErrorMessage ={0}必须至少{2}字符长。,MinimumLength = 6)]
        [数据类型(DataType.Password)
        公共字符串密码{搞定;组; }        [数据类型(DataType.Password)
        [比较(密码的ErrorMessage =密码和确认密码不匹配。)
        公共字符串ConfirmPassword {搞定;组; }    }    [Serializable接口]
    公共类RegisterStep2ViewModel:IStepViewModel
    {        [显示(名称=名字的ResourceType = typeof运算(Resources.Resources))]
        公共字符串名字{获得;组; }        [显示(名称=姓氏的ResourceType = typeof运算(Resources.Resources))]
        公共字符串名字{获得;组; }        [非序列化]
        私人HttpPostedFileBase _file;
        公共HttpPostedFileBase文件
        {
            得到
            {
                返回_file;
            }
            组
            {
                _file =价值;
            }
        }        [显示(名称=生日,的ResourceType = typeof运算(Resources.Resources))]
        [数据类型(DataType.Date)
        [DisplayFormat(DataFormatString ={0:YYYY / MM / DD},ApplyFormatInEditMode = TRUE)]
        公众的DateTime?生日{搞定;组; }        [显示(名称=全国code的ResourceType = typeof运算(Resources.Resources))]
        公众诠释国家code {搞定;组; }        [显示(NAME =性别的ResourceType = typeof运算(Resources.Resources))]
        公共BOOL IsMale {搞定;组; }        [显示(名称=移动的ResourceType = typeof运算(Resources.Resources))]
        公共字符串MobilePhone {搞定;组; }        [显示(名称=国家的ResourceType = typeof运算(Resources.Resources))]
        公共字符串国家{搞定;组; }        [显示(NAME =地址,的ResourceType = typeof运算(Resources.Resources))]
        公共字符串地址{搞定;组; }        [MustBeTrue]
        公共BOOL CaptchaValid {搞定;组; }
    }}

下面是我的控制器

  [使用AllowAnonymous]
    公众的ActionResult指数()
    {
        VAR向导=新RegisterWizardViewModel();
        wizard.Initialize();
        返回视图(向导);
    }    [HttpPost]
    [使用AllowAnonymous]
    [ValidateAntiForgeryToken]
    公众的ActionResult指数([反序列化] RegisterWizardViewModel向导,RegisterWizardViewModel.IStepViewModel步)
    {
        wizard.Steps [wizard.CurrentStepIndex] =步;        如果(ModelState.IsValid)
        {
            如果(!string.IsNullOrEmpty(请求[下一步]))
            {
                wizard.CurrentStepIndex ++;            }
            否则,如果(!string.IsNullOrEmpty(请求[preV))
            {
                wizard.CurrentStepIndex--;
            }
            其他
            {                VAR模型1 = wizard.Steps [0]作为RegisterWizardViewModel.RegisterStep1ViewModel;
                变种模型2 = wizard.Steps [1]作为RegisterWizardViewModel.RegisterStep2ViewModel;
                变种UploadedFile的=(model2.File =空&放大器;!&放大器; model2.File.ContentLength大于0)?新的字节[model2.File.InputStream.Length]:空;
                如果(UploadedFile的!= NULL)
                {
                    model2.File.InputStream.Read(UploadedFile的,0,uploadedFile.Length);
                }                VAR用户=新ApplicationUser {用户名= model1.Email,电子邮件= model1.Email,名字= model2.FirstName,姓氏= model2.LastName,图像= UploadedFile的,生日= model2.BirthDay,IsMale = model2.IsMale,全国code = model2.National code,MobilePhone = model2.MobilePhone,国家= model2.Country,地址= model2.Address};
                VAR的结果= UserManager.Create(用户,model1.Password);
                如果(result.Succeeded)
                {
                    SignInManager.SignIn(用户,isPersistent:假的,rememberBrowser:假);                    返回JSON(新{响应=重定向,URL = Url.Action(指数,家)});
                }
                其他
                {
                    AddErrors(结果);
                }            }        }
        否则,如果(!string.IsNullOrEmpty(请求[preV))
        {
            wizard.CurrentStepIndex--;
        }        返回视图(向导);
    }

和我使用这个jQuery code通过Ajax调用我registerwizard索引视图提交。

  @section脚本{
&LT;脚本SRC =〜/脚本/ jquery.unobtrusive-ajax.min.js&GT;&LT; / SCRIPT&GT;
&LT;脚本类型=文/ JavaScript的&GT;
    $(函数(){
        $('形式')。在(提交,功能(E){
            亦即preventDefault;
            如果($(本).valid()){
                $阿贾克斯({
                    网址:this.action,
                    类型:this.method,
                    数据:$(本).serialize()
                    成功:函数(结果){
                        window.location的= result.url;
                    }
                });
            }
            返回false;
        });
    });&LT; / SCRIPT&GT;}

那么现在的问题就是控制犯规识别哪些按钮已被pressed和请求[下一步] 请求[preV] 总是返回null,模型状态的有效期为第一步的情况下(电子邮件,传球,confirmpass),控制器直接进入创建用户。其值得一提的是,因为我不能获得通过Ajax调用我不知道第二步时是否文件上传和日期时间属性发送到控制器没有任何问题或没有。结果
更新:结果
这里是索引视图

  @using(Html.BeginForm(指数,RegisterWizard,FormMethod.Post,新{@class =形横,角色=形式,ENCTYPE = 的multipart / form-data的}))
    {
        @ Html.AntiForgeryToken()        @ Html.Serialize(向导,模型)        @ Html.Hidden(步骤类型,Model.Steps [Model.CurrentStepIndex] .GetType())
        @ Html.EditorFor(X =&GT; currentStep,NULL,)
        如果(Model.CurrentStepIndex大于0)
        {
            &LT; D​​IV CLASS =COL-XS-9 COL-SM-6 COL-MD-5 COL-LG-5的风格=填充右:0像素;&GT;
                &LT;输入类型=提交级=BTN BTN-默认值=previousNAME =preV/&GT;            &LT; / DIV&GT;
        }        如果(Model.CurrentStepIndex&下; Model.Steps.Count - 1)
        {
            &LT; D​​IV CLASS =COL-XS-10 COL-SM-8 COL-MD-6的风格=&GT;
                &LT;输入类型=提交级=BTN BTN-默认值=下一步NAME =下一步风格=浮动:左;/&GT;            &LT; / DIV&GT;
        }
        其他
        {
            &LT; D​​IV CLASS =COL-XS-3 COL-SM-6 COL-MD-7 COL-LG-7的风格=填充右:0像素;&GT;                &LT;输入类型=提交级=BTN BTN-默认值=完成NAME =完成/&GT;            &LT; / DIV&GT;
        }
    }


解决方案

好了,在别人的情况下,面临着这个问题,可能该类似的问题我解释一下我的解决方法。结果
主要问题认识哪个按钮已提交形式:结果我已经添加了一个隐藏的输入命名按钮和每个按钮上单击事件动态地更改其名称通过jQuery终于修改了我的控制器,以获得要求此值
以下是其中包含整个窗体和我的控制器的动作后局部视图。结果

  @using Microsoft.Web.Mvc
@model Models.RegisterWizardViewModel@ {
    VAR currentStep = Model.Steps [Model.CurrentStepIndex]
}@using(Html.BeginForm(指数,RegisterWizard,FormMethod.Post,新{@class =形横,角色=形式,ENCTYPE =的multipart / form-data的@id = mainRWF}))
{
    @ Html.AntiForgeryToken()
    @ Html.Hidden(按钮)
    @ Html.Serialize(向导,模型)
    @ Html.Hidden(步骤类型,Model.Steps [Model.CurrentStepIndex] .GetType())
    @ Html.EditorFor(X =&GT; currentStep,NULL,)    如果(Model.CurrentStepIndex大于0)
        {
           &LT; D​​IV&GT;
              &LT;输入类型=提交值=previousNAME =preV/&GT;
           &LT; / DIV&GT;
        }    如果(Model.CurrentStepIndex&下; Model.Steps.Count - 1)
        {
          &LT; D​​IV&GT;
            &LT;输入类型=提交值=下一步NAME =下一个/&GT;
          &LT; / DIV&GT;
        }
    其他
        {
          &LT; D​​IV&GT;
            &LT;输入类型=提交值=提交名称=完成/&GT;
          &LT; / DIV&GT;
        }
 }

...

  [ValidateAntiForgeryToken]
    公共异步任务&LT;&的ActionResult GT;指数([反序列化] RegisterWizardViewModel向导,RegisterWizardViewModel.IStepViewModel步)
    {
       wizard.Steps [wizard.CurrentStepIndex] =步;        如果(ModelState.IsValid)
        {
            如果(Request.Form.GetValues​​(按钮)。包含(下一步))
            {
                wizard.CurrentStepIndex ++;            }
            否则,如果(Request.Form.GetValues​​(按钮)。包含(preV))
            {
                wizard.CurrentStepIndex--;
            }
            其他
            {
                //做的东西与接收到的值
                返回JSON(新{响应=成功});            }       }
       否则,如果(Request.Form.GetValues​​(按钮)。包含(preV))
       {
           //即使验证失败,我们允许用户
           //浏览到previous步骤
           wizard.CurrentStepIndex--;
       }
       否则,如果(!ModelState.IsValid)
       {
           //如果我们通过将本到HTML(成功的)FUNC阿贾克斯走到这一步,事情失败了,重新显示形式错误
           返回PartialView(_ IndexPartial向导);
       }    //返回下一步
    返回PartialView(_ IndexPartial向导);}

显然我得到了文件上传的问题!而选择HTML5 FORMDATA处理上传的Ajax调用的Finish按钮的数据选择。结果,我会appriciate这个解决方案的意见,以使它更好。

I've used Darin-Dimitrov's approach for making a multi-step register form which is explained Here and it works fine. Now i want to handle submit events for Previous,Next and Finish buttons using jquery ajax instead of Html.Beginform().

Notes:

  • I'm using MVC 5 with .NET 4.5.2
  • I've fileupload and datetime properties in my second step viewmodel.

Here is my 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; }
    }

}

Here is My Controller

 [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);
    }

And i've used this jquery code for submit via ajax call in my registerwizard index view.

@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>

}

Well now the problem is controller doesnt recognize which button has been pressed and Request["next"]or Request["prev"] always return null and in case of model state being valid for first step (Email,pass,confirmpass), controller directly goes to creating user. its worth mentioning that since i couldnt get to second step via ajax call i dont know whether if file upload and datetime property sent to controller without any problem or not.
Update:
Here is Index View

  @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>


        }
    }

解决方案

Well, in case of someone faces this issue and probably has similar problem i explain my workaround.
main issue recognizing which button has been submitted the form:
i've added one hidden input named Button and change its name dynamically via jquery on click event on each button and finally modified my controller to get this value from request.
followings are partial view which holds entire form and post action of my controller.

@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);

}

and obviously i got problems with file upload! and chose html5 formData to handle uploading as data option of ajax call for finish button.
i would appriciate comments on this solution in order to make it better.

这篇关于根据ASP.NET MVC5 splited的ViewModels在多级寄存器形式实现jQuery的阿贾克斯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆