Using a Partial view with IF/ELSE statements to display content

Topics: Troubleshooting
Jun 16, 2011 at 3:27 PM

I have been busy trying to port my site over to Orchard (YAY!).  Windows 7/Web Matrix/Orchard 1.2. I was already using MVC3/Razor/C# on the old site.

One of the things I did on my old site was to use Partials and then use @if / else if / else statements to display content specific to a controller.  Say, Controller 1, Controller 2, etc.

So, inside a partial, I had something like the following:

 

@if (ViewContext.Controller is MyNameSpace.Controllers.Controller1)

{ <CONTENT specific to Controller 1> }

else if (ViewContext.Controller is MyNameSpace.Controllers.Controller2)

{ <CONTENT specific to Controller 2> }

else

{ <DEFAULT CONTENT> }

 

Now, with Orchard, obviously I am getting the namespace compliation error for MyNameSpace not being found.

Any ideas on how I would be able to implement this in Orchard using the partials I've already created? Since I am basing the conditions on the Controller being used, I suspect it won't be as easy as just using the appropriate Orchard namespace.

For a bit more clarification:  The Controller1 and 2 used above will basically be either links in the main navigation menu used in Orchard (there will be more than 2, for this discussion I just oversimplified), or will be based on Chapters which I plan to utilize to organize content.

Otherwise, if I am forced out of using "controllers" in this sense, is there some other way that I can implement this functionality.

As always, thank you in advance for any guidance/assistance/links/etc.

-REM

Jun 16, 2011 at 4:41 PM

Well, for various reasons that's not a great way to do things :)  With MVC each action on your controller can render a different view. So why would you need to do that switch in the view? It's kind of defeating the MVC pattern. Your controllers should decide which view to display, and feed in the model for it to use. You want to avoid this kind of logic completely in the view.

Even then - there's no reason why you can't do that in Orchard. You can use whatever namespace you like in your module.

However, you haven't detailed exactly what functionality you're trying to implement, and there are quite possibly easier and more Orchard-specific ways to achieve what you need. So if you can furnish more detail about a given task I can maybe elaborate.

 

Jun 16, 2011 at 5:03 PM
Edited Jun 16, 2011 at 5:04 PM

Thanks for the help.

What I've started to do with Orchard is customize the theme to get the same look/layout of my original MVC3 site.

I've implemented a footer (Footer.cshtml) in the /Views folder of my theme by using the Designer Tools (selecting an Alternate).

In the footer, I have an informational area that will be consistent throughout the site (it is above the standard footer code with links/etc.).

In this information area I have, for example, a partial with the headline "Why Choose Us?". Within that partial I have just basic text; however, I want the text to render differently for each of the different services I provide, depending on which "Service" the user is viewing on the browser.

In essence, for Service # 1 (which, going on my original post, used Controller1 in my old MVC3 site) it says "Our Service #1 Solutions are . . . ."  Some of the text thereafter is also unique to Service #1.

Service #1 is a link on my main navigational bar, which is also consistent throughout the site.  I also had all my Service #1 pages in its own folder as was the convention with Controllers. There are multiple pages in the Service #1 folder.  Basically, when the user is on any one of those Service #1 pages, they saw the text in the information panel that was specific to Service #1.

Whenever a user goes to a Service #2 page (which also has its own folder/controller/set of multiple pages), I wanted that "Why Choose Us?" partial to just display alternate text specific to Service# 2, so it says "Our Service #2 Solutions are...." with additional text thereafter which is unique to Service #2.

I also have default text for that "Why Choose Us?" partial, which is just generic for the standard website pages (Home Page, Contact Us, About, Disclaimer, etc.).

So, my original logic that I am trying to implement is something like this:

If its a "Service #1" page > show "Service #1" text;

Else if its a "Service #2" page > show "Service #2" text;

Else > show default text.

My incorrect implementation was just my quick fix because I originally ported everything over from .aspx pages I previously had (Web Forms) for the site. Back then I had this logic implemented in a code-behind.

I hope that's clearer and that I haven't made it more convoluted.

Jun 16, 2011 at 6:50 PM
Edited Jun 16, 2011 at 6:50 PM

Yup, I can see what you're trying to do now.

The great (or possibly confusing!) thing about Orchard is that there are probably a dozen or so different ways to set things up like that.

Firstly; there's nothing stopping you using the same Controllers in Orchard. It's built on MVC. Orchard modules and themes are actually MVC "areas" and they can have their own routes and controllers. You just have an extra bit at the start of the url: /ModuleName/ControllerName/ActionName. Then all you need to do is add the [Themed] attribute either to your controller or individual actions and they'll get the whole Orchard template wrapped around the View.

So with that you can probably get things running exactly as they were in your old site.

Now to get your custom footer partial for each type of controller, there's a really easy and Orchard-specific way you can do that. Here's an example of a controller that pushes a template into the Footer zone:

 

    [Themed]
    public class DemoController : Controller
    {
        private readonly IShapeFactory _shapeFactory;
        private readonly dynamic Shape;

        public IOrchardServices Services { get; set; }

        public DemoController(
            IOrchardServices services,
            IShapeFactory shapeFactory
            )
        {
            Services = services;
            Shape = _shapeFactory = shapeFactory;
        }

        public ActionResult DemoAction()
        {
            Services.WorkContext.Layout.Footer.Add(Shape.DemoShape(Text: "Hello!"));
            return View("DemoView");
        }
    }

 

What the above does is load a "shape" (which are Orchard's fancy versions of partials) called DemoShape, and display it in the footer area. Orchard will look for a file called DemoShape.cshtml in the Views folder of your module/theme. In fact it will look in all modules and themes, and take the highest priority one. So later on you could create a new theme and base it on your existing one; then add an override for DemoShape.cshtml to customise that template just for that theme. It's a lot more flexible than partials.

The other thing to note is that I passed a property into the shape, called Text. You can access this from DemoShape.cshtml with @Model.Text - Model is a dynamic object in Orchard views, unless you specify a model type.

That's just one way of achieving the same result. Orchard also has a system of layers and widgets, which allows you to define rules for when certain things show in certain zones. It comes with a HtmlWidget which would suit your purpose, and you could define layer rules based on URL for instance to control which blocks show up when, and then just create your Service pages as ordinary content Pages.

I could list other techniques for customising layouts and templates that you might find useful, but maybe that's enough for you to be going on with!

Jun 16, 2011 at 9:07 PM

Thanks for your efforts. I looked into the layers/widget suggestion as it seemed easiest to implement in the short amount of time I had. I also enabled the Tagged module from the Gallery, and I was able to do what I wanted using tags for each service ... sort of. One of my "partials" has @Html.ActionLink's, which I can't use inside the HTML widget. Sorry, but I am new to Orchard, and I suspect its a silly thing not to be able to do. I haven't tried to insert just regular <a> links yet (have to get going to work) - but in a way I feel that outdoes the purpose of using Razor :(. I can probably spend some time also figuring out how to get that working in the actual footer I implemented (I just threw up test pages with test content to check if it would work).

I then began with your more detailed suggestion (thank you, again, for that), as I could really see some use for other parts of my site. Now, for another silly question: I originally started using the "source" with VS2010 Pro (1.1), but then because I really wanted to spend time getting to know Orchard I went the WebMatrix route.  I know I can switch back and forth, but basically I've been using the "web" version of Orchard (1.2) to do all of this. So my question is, based on the "web" version, where am I to put my Controller folder? In my Theme? Under the root? I've been so used to (I know many people are against this) VS2010 setting up my folders for my projects that I may just need a knock in the head. :)

Sorry for the silly questions.

Jun 17, 2011 at 10:26 AM
Edited Jun 17, 2011 at 10:27 AM

No problem,

Using @Html.ActionLink could be a good idea, it depends what you're trying to do. The shape created from the controller could take area/controller/action parameters and then render the link from them, that's much better than hard-coded HTML links, and then for each action you can control by code what that bit of the template links to.

There's no real different between web or source versions of Orchard. You can still use Webmatrix with the full source, on the src/Orchard.Web folder. I usually have Webmatrix and VS Express running at the same time - Webmatrix is a bit faster, but when I need to debug I fire it up in VS.

You shouldn't ever add any code to Orchard's root - it should always be in a theme or module. So you can put your controller in a /Controllers folder under your theme. However, your theme will need its own .csproj for this. Did you generate it using codegen, or just by hand? To be honest if I'm writing any non-trivial code like a controller, I'll probably put it in its own module instead of the theme. You can use the Orchard command line to build a new module with "codegen module MyNameSpace.MyModuleName" and all the basic files will be created for you, along with subfolders for Controllers, Views, etc. If you're codegenning a theme you can use /CreateProject:true to ensure it includes a .csproj file and will therefore be a full MVC area capable of having its own controllers etc.

Jun 17, 2011 at 5:33 PM

You sir are a scholar and a gentleman. ;) Thanks.

I did Codegen my theme (I did a "BasedOn" at first, then restarted everything and did a "CreateProject").

I'm getting along better with the help you provided.