November Happy Hour will be moved to Thursday December 5th.

Create a page to display partial views

Vote:
 

I'm brand new to EPiServer and am trying to gauge what the equivalent of part of a current MVC 2 site we host would be in EPiServer. The site lets you enroll in classes and takes you through a series of wizard-like forms. For instance, in order, you might visit:

  • site/Enroll/ChooseClass/
  • site/Enroll/AddStudent/
  • site/Enroll/ChooseStudent/
  • site/Enroll/Tuition/
  • site/Enroll/Cart/

Each of those actions returns a different view containing a form for the user to work with. If we go with EPiServer for our site, it would need to have an equivalent of this /Enroll/ section of the site and none of its views would be interacting with the CMS content. Right now I'm just trying to figure out how to mock this up at the "Hello World" complexity level but so far am stuck. Here's what I've tried:

What I don't want to do is create a page type for every page involved. So I created one new page type named OEPage. I wanted to give a content editor some way of creating each page and choosing the wizard step view...for lack of a better term. So I gave the page an Enum property for the "control type" it should display.

    [ContentType(DisplayName = "OEPage", GUID = "7484998f-3c37-4e35-8489-f62718c4fb08", Description = "")]
    public class OEPage : SitePageData
    {
        /*
                [CultureSpecific]
                [Display(
                    Name = "Main body",
                    Description = "The main body will be shown in the main content area of the page, using the XHTML-editor you can insert for example text, images and tables.",
                    GroupName = SystemTabNames.Content,
                    Order = 1)]
                public virtual XhtmlString MainBody { get; set; }
         */

        [Display(Name = "OE Control Type",
                 Description = "The OE control to load on this page.",
                 GroupName = SystemTabNames.Content,
                 Order = 1)]
        [BackingType(typeof(PropertyNumber))]
        [EditorDescriptor(EditorDescriptorType = typeof(EnumEditorDescriptor))]
        public virtual OEControlType ControlType { get; set; }
    }

    public enum OEControlType
    {
        None = 0,
        AddStudent
        SelectStudent,
        Class_EnrollTuition,
        Class_EnrollTrial,
        ShoppingCart,
        Checkout,
    }

Then I created a new page for the Select Student step and set the ControlType property to SelectStudent. Now in a view I could add the conditional razor code to display different partial views. The only problem is the partial views will all need to work on their own view model...oh and this is really ugly and tightly coupled. I'm getting a little confused with all the custom routing and template mapping in EPiServer. What would be a better way to have one page type for pages that follow the above URL format to display various user input forms? Some of the views will also need perform do async actions in response to user input. Ideally a content editor could drag and drop the appropriate view onto each page and configure properties for it. Should I convert my OEPage.ControlType property to a block and create each view as a block?

#118295
Mar 04, 2015 1:17
Vote:
 

I guess the simplest solution is to create separate page types for different forms.
You don't have to deal with partial routing, selection factories, etc.

And then just group them in edit mode by setting GroupName value.

[ContentType(
	GUID = "920cbce2-66b9-4c73-a066-a600bb3e7a14",
	GroupName = "Enrolment forms")]
public class AddStudentPage : PageData

[ContentType(
	GUID = "88302c8a-08d5-4938-8dfa-12a097b9f2ba",
	GroupName = "Enrolment forms")]
public class EnrolTrialPage : PageData


Editors like it more than dropdowns :)

#118316
Edited, Mar 04, 2015 10:44
Vote:
 

Benefit for having separate page type for form is that editor can access this page in EditMode, probably preview how it may look, add some editorial stuff to it (if applicable and needed here) and have some other cool scenarios how to work with content there.

#118338
Mar 04, 2015 15:43
Vote:
 

Thanks for your responses. I've been toying around with using blocks for the form content of a single page type. I tried to have the blocks inherit from a common base type and then to give my page type a property of that base type so that an editor could only add block instances of the base type to my page. That didn't seem to be supported by the editor so I settled for a ContentArea that could potentially contain any type of Block. After that, it was all going great until I realized you can't really redirect to the next page in the block controller's Post action because it's a child action and rendering the view has already begun. Bummed! In the process, I started thinking, "I'm really not doing any less work by going this route, so why is it my preference?"

First, creating one page type per view just seems too tightly coupled. If the page type is identical between all the views, they should be able to share it. My page types would literally, probably not have any properties; they'd just be an empty class for the sake of existance. Second, having this long list of page types showing in the screenshot above isn't ideal because each will only ever be used once. After one of each is created, they're just clutter an editor has to try not to look at. These page types should be reusable items, in my opinion. It would be much better to have one page type and be able to choose which form displays on the instance of that page, the same way we do with any other page content. That's what I was trying to do with the Blocks, but are we saying that it's not possible to have custom forms as page content in EPiServer? (I've seen XForms, but I will need complete control over the forms).

With either approach, it creates a lot of controllers and each view has to have it's own view folder under Views/...that's going to become a long list. In standard MVC, I have these all sharing a single controller and the route allows the views to be in a Views/Enroll/ folder, which helps keep the project organized. In EPiServer, if I want to organize controllers and views into subfolders, it looks like I might be able to register some addditional search locations by creating a custom view engine? I've seen a few forum/blog posts on this but haven't gotten into them yet. On another note, is it possible to give the actual view templates names more meaningful than Index.cshtml? It gets pretty confusing when you're working in visual studio and have multiple tabs open named Index.cshtml. I underlined my questions since they got a little drowned out. Thanks for your help! 

#118423
Edited, Mar 06, 2015 0:56
Vote:
 

Hi Jesse,

I'll try to answer some of the questions:

I tried to have the blocks inherit from a common base type and then to give my page type a property of that base type so that an editor could only add block instances of the base type to my page. That didn't seem to be supported by the editor so I settled for a ContentArea that could potentially contain any type of Block.

You can use AllowedTypes attribute on ContentArea to restrict block types.

After that, it was all going great until I realized you can't really redirect to the next page in the block controller's Post action because it's a child action and rendering the view has already begun.

Instead of calling controller actions on block controller, you could create a WebAPI and send ajax requests.

If the page type is identical between all the views, they should be able to share it.

You can take a look at AlloyTech sample website. The Layout page uses IPageViewModel<SitePageData> model. You can have something similar.

Second, having this long list of page types showing in the screenshot above isn't ideal because each will only ever be used once.

Agree. It would be nice to have API methods that filter the list of available content types. But at least in EPiServer 8 you can change the order of groups and put those forms at the very bottom of the list :)

That's what I was trying to do with the Blocks, but are we saying that it's not possible to have custom forms as page content in EPiServer?

We created forms as blocks because we want the developers to have a full control over forms, not the editors. Blocks can be dragged&dropped into the XhtmlString field. And we created a custom attribute (similar to AllowedTypes) and IValidate<PageData> validator so that we can controll which block types can be added to XhtmlString fields.

On another note, is it possible to give the actual view templates names more meaningful than Index.cshtml?

You can have something like this in your block controller:

public override ActionResult Index(BlockData currentBlock)
{
    return PartialView("~/Views/MyFolder/MyView.cshtml", currentBlock);
}
#118433
Mar 06, 2015 10:00
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.