[MVC] Trying to create a Registration Wizard With SurfaceController
Hello all,
As stated in the post's title, I'm trying to create a multistep registration form which doesn't depend directly on javascript, so AJAX is not a choice here. First at all, I'm unsure of how people works with the Templates in the umbraco Settings page. What I have currently is a doc type called MembersRegister which takes a razor template I created using Umbraco. I created a model which contains a subset of models, one for each wizard step, and every wizard step uses its own partial view.
Then I've created a model which contains 3 submodels, one for each registration step:
RegistrationViewModel.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Project.Models
{
/**
* Step 1 View model
*/
public class RegisterStep1ViewModel
{
public string Referer { get; set; }
[Required]
public bool IsRefered { get; set; }
[Required]
public bool IsAffiliate { get; set; }
}
/**
* Step 2 View model
*/
public class RegisterStep2ViewModel
{
public string HeardAboutText { get; set; }
public string JoinReasontext { get; set; }
[Required]
public string Country { get; set; }
}
/**
* Step 3 View model
*/
public class RegisterStep3ViewModel
{
[Required]
public bool MemberPolicyAccepted { get; set; }
[Required]
public bool AffiliatePolicyAccepted { get; set; }
}
/**
* Container
*/
public class RegisterWizardViewData
{
public RegisterStep1ViewModel Step1 { get; set; }
public RegisterStep2ViewModel Step2 { get; set; }
public RegisterStep3ViewModel Step3 { get; set; }
public RegisterWizardViewData()
{
Step1 = new RegisterStep1ViewModel();
Step2 = new RegisterStep2ViewModel();
Step3 = new RegisterStep3ViewModel();
}
}
}
My surface controller:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Project.Models
{
/**
* Step 1 View model
*/
public class RegisterStep1ViewModel
{
public string Referer { get; set; }
[Required]
public bool IsRefered { get; set; }
[Required]
public bool IsAffiliate { get; set; }
}
/**
* Step 2 View model
*/
public class RegisterStep2ViewModel
{
public string HeardAboutText { get; set; }
public string JoinReasontext { get; set; }
[Required]
public string Country { get; set; }
}
/**
* Step 3 View model
*/
public class RegisterStep3ViewModel
{
[Required]
public bool MemberPolicyAccepted { get; set; }
[Required]
public bool AffiliatePolicyAccepted { get; set; }
}
/**
* Container
*/
public class RegisterWizardViewData
{
public RegisterStep1ViewModel Step1 { get; set; }
public RegisterStep2ViewModel Step2 { get; set; }
public RegisterStep3ViewModel Step3 { get; set; }
public RegisterWizardViewData()
{
Step1 = new RegisterStep1ViewModel();
Step2 = new RegisterStep2ViewModel();
Step3 = new RegisterStep3ViewModel();
}
}
}
And here's an example of one of my steps:
@inherits Umbraco.Web.Mvc.UmbracoViewPage<Project.Models.RegisterWizardViewData>
@{
}
<h2 class="subtitle light">@Project.TranslationUtils.TranslateDictKey("Register with us description bla bla bla bla")</h2>
<div class="span6 testi">
<p style="text-align:right">@Project.TranslationUtils.TranslateDictKey("Your Referer")</p>
</div>
<div class="span15">
@using (Html.BeginUmbracoForm("RegisterWizardStep1", "ProjectRegistrationSurface", new { language = System.Threading.Thread.CurrentThread.CurrentCulture.Name }))
{
<text>
@Html.TextBoxFor(x => x.Step1.Referer, new { id = "referer", @class = "input-text", style="width:360px" })
<br />
<label class="input" for="yesReferer" style="margin:10px">
@Html.RadioButtonFor(x => x.Step1.IsRefered, true, new { id = "yesReferer" })
@Project.TranslationUtils.TranslateDictKey("RegisterKnowsRefeererText")
</label>
<label class="input" for="noReferer">
@Html.RadioButtonFor(x => x.Step1.IsRefered, false, new { id = "noReferer" })
@Project.TranslationUtils.TranslateDictKey("RegisterDoesntKnowsRefeererText")
</label>
<br /><br />
<h2>@Project.TranslationUtils.TranslateDictKey("RegisterIWantToSignUpAs")</h2>
<br />
<div id="registrationChoices" style="width:360px;">
<ul style="list-style: none">
<li>
<label class="input" for="asMember">
@Html.RadioButtonFor(x => x.Step1.IsAffiliate, false, new { id = "asMember", style="margin:8px" })
@Project.TranslationUtils.TranslateDictKey("RegisterMemberChoiceText")
</label>
</li>
<li>
<label class="input" for="asAffiliate">
@Html.RadioButtonFor(x => x.Step1.IsAffiliate, true, new { id = "asAffiliate", style="margin:8px" })
@Project.TranslationUtils.TranslateDictKey("RegisterAffiliateChoiceText")
</label>
</li>
</ul>
<br /><br />
</div>
<input class="submit" type="submit" value="@Project.TranslationUtils.TranslateDictKey("Send")"/>
<br/><br />
<p>@Html.ValidationMessage("WizardError")</p>
<div id="status"></div>
</text>
}
</div>
My questions are:
a)How does people usually work with this scenario when one has to in a single document? I would really appreciate some good tips and procedures to carry on this kind of issues. Thank you all for your time.
b) Do they(you) work with umbraco documents(diffenent docs or same) or do you work directly with Views? In this last case, how do you Inherit your doc's layout?
c) When working with CurrentUmbracoPage() and RedirectToCurrentUmbracoPage(), I must pass the model via TempData or similar between my controller's actions/views, and I don't feel confortable with that. If I use return View(), it'll look for a _Layout.cshtml which I current don't have. All I want is to use my document's layout, but I don't know the right way of doing this.
Hi, the system doesn't show the edit link anymore for some reason... I am attaching the SurfaceController here. As you can see I keep reinjecting the TempData with the register form data from every step.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using Project.Models;
namespace Project.Controllers
{
public class ProjectRegistrationSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
const string TEMP_DATA_CURRENT_STEP = "currentStep";
const string TEMP_DATA_WIZARD_OBJECT = "RegistrationData";
public PartialViewResult RegisterWizard(RegisterWizardViewData model)
{
if (TempData[TEMP_DATA_CURRENT_STEP] == "2")
{
RegisterWizardViewData wiz = (RegisterWizardViewData)TempData[TEMP_DATA_WIZARD_OBJECT];
TempData[TEMP_DATA_WIZARD_OBJECT] = wiz;
return PartialView("_WizardStep2", (RegisterWizardViewData)wiz);
}
if (TempData[TEMP_DATA_CURRENT_STEP] == "3")
{
RegisterWizardViewData wiz = (RegisterWizardViewData)TempData[TEMP_DATA_WIZARD_OBJECT];
TempData[TEMP_DATA_WIZARD_OBJECT] = wiz;
return PartialView("_WizardStep3", (RegisterWizardViewData)wiz);
}
RegisterWizardViewData rw = new RegisterWizardViewData();
return PartialView("_WizardStep1", rw);
}
[HttpPost]
public ActionResult RegisterWizardStep1(RegisterStep1ViewModel step1)
{
RegisterWizardViewData wholeModel = new RegisterWizardViewData
{
Step1 = step1
};
string errors = "";
if (!ModelState.IsValid)
{
foreach (ModelState modelState in ViewData.ModelState.Values)
{
foreach (ModelError error in modelState.Errors)
{
errors += String.Format("<p>{0}</p>", error.ErrorMessage);
}
}
ModelState.AddModelError("WizardError", "Please complete all the required fields" + errors);
return CurrentUmbracoPage();
}
if (step1.IsRefered && String.IsNullOrEmpty(step1.Referer))
{
ModelState.AddModelError("WizardError", "Please enter your refereers name in the case you were referer" + errors);
return CurrentUmbracoPage();
}
TempData[TEMP_DATA_CURRENT_STEP] = "2";
TempData[TEMP_DATA_WIZARD_OBJECT] = wholeModel;
return RedirectToCurrentUmbracoPage();
}
[HttpPost]
public ActionResult RegisterWizardStep2(RegisterStep2ViewModel step2)
{
if (String.IsNullOrEmpty(step2.Country))
{
ModelState.AddModelError("WizardError", "Please complete all the required fields");
return CurrentUmbracoPage();
}
RegisterWizardViewData wholeModel = (RegisterWizardViewData)TempData[TEMP_DATA_WIZARD_OBJECT];
if (!wholeModel.Step1.IsRefered)
{
ModelState.AddModelError("WizardError", "Please complete all the required fields");
return CurrentUmbracoPage();
}
wholeModel.Step2 = step2;
TempData[TEMP_DATA_WIZARD_OBJECT] = wholeModel;
TempData[TEMP_DATA_CURRENT_STEP] = "3";
return RedirectToCurrentUmbracoPage();
}
[HttpPost]
public ActionResult RegisterWizardStep3(RegisterStep3ViewModel model)
{
RegisterWizardViewData wholeModel = (RegisterWizardViewData)TempData[TEMP_DATA_WIZARD_OBJECT];
TempData[TEMP_DATA_CURRENT_STEP] = "3";
TempData[TEMP_DATA_WIZARD_OBJECT] = model;
if (wholeModel.Step1.IsAffiliate)
{
if (!model.MemberPolicyAccepted || !model.AffiliatePolicyAccepted)
{
ModelState.AddModelError("WizardError", "You must accept both policies");
return CurrentUmbracoPage();
}
}
else
{
if (!model.MemberPolicyAccepted)
{
ModelState.AddModelError("WizardError", "You must accept the policy");
return CurrentUmbracoPage();
}
}
wholeModel.Step3 = model;
TempData[TEMP_DATA_WIZARD_OBJECT] = model;
// Next steps or process the data.
return Content("Form data received!");
}
}
[MVC] Trying to create a Registration Wizard With SurfaceController
Hello all,
As stated in the post's title, I'm trying to create a multistep registration form which doesn't depend directly on javascript, so AJAX is not a choice here. First at all, I'm unsure of how people works with the Templates in the umbraco Settings page. What I have currently is a doc type called MembersRegister which takes a razor template I created using Umbraco. I created a model which contains a subset of models, one for each wizard step, and every wizard step uses its own partial view.
My files looks like this:
Umbraco template:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage @{ Layout = "Members.cshtml"; Umbraco.RenderMacro("SetPageCulture"); } @section bodyClass {@("single-alt")}
@Html.Action("RegisterWizard", "ProjectRegistrationSurface")
Then I've created a model which contains 3 submodels, one for each registration step:
RegistrationViewModel.cs:
My surface controller:
And here's an example of one of my steps:
My questions are:
a)How does people usually work with this scenario when one has to in a single document?
I would really appreciate some good tips and procedures to carry on this kind of issues.
Thank you all for your time.
b) Do they(you) work with umbraco documents(diffenent docs or same) or do you work directly with Views? In this last case, how do you Inherit your doc's layout?
c) When working with CurrentUmbracoPage() and RedirectToCurrentUmbracoPage(), I must pass the model via TempData or similar between my controller's actions/views, and I don't feel confortable with that. If I use return View(), it'll look for a _Layout.cshtml which I current don't have. All I want is to use my document's layout, but I don't know the right way of doing this.
You duplicated your models in surfacecontrollers, could you update this?
Hi, the system doesn't show the edit link anymore for some reason... I am attaching the SurfaceController here. As you can see I keep reinjecting the TempData with the register form data from every step.
}
I know the post is closed, but when I do a step by step follow this blog post
http://umbraco.com/follow-us/blog-archive/2015/2/13/creating-multi-step-forms-using-a-surfacecontroller/
is working on a reply...