Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

Taking over list rendering in Orchard

OooohA task that is likely to pop-up oftentimes when customizing an Orchard theme for a project is list rendering. Two types of shapes will typically be at work when rendering a list in Orchard: the summary shape and the list shape.

The list shape itself will rarely vary as the semantics of a list pretty much mandate the use of a simple UL/LI decorated with CSS classes. It's so simple in fact that it's not even rendered by a template but by a C# shape method in CoreShapes.cs.

The summary shapes can be rendered by templates that are specialized by content type and by display type. That covers most cases of list customization.

In a few rare cases though, you'll want to simply take over the rendering of a specific list completely.

In my LIDNUG demo last Monday, I had changed the item summary template so that my blog post summaries would show a little richer than the default template:A customized summary template

This caused the recent posts widget to also change appearance, and not in a good way, because it's using the same default summary template:The summary template affects recent posts.

All we really want in there is a link to the post. At this point, I could have changed the code of the widget so that it would use a different display type, or I could just take over rendering. I opted for the latter. Let's look at the Parts.Blogs.RecentBlogPosts.cshtml template that I put into my theme's Views folder…

The template is extremely simple once you've got hold of the list of posts. The code for this is a little weird, admittedly:

IEnumerable<object> blogPosts = Model.ContentItems.ContentItems;

Model here is the widget's shape. It has a ContentItems property, which really is a List shape. The list shape itself has a ContentItems property and that last one is the actual list of blog posts. Once we have this, we just need to loop over the posts and display a simple link for each of them:

<ul class="content-items">
@foreach (dynamic post in blogPosts) {
    string title = post.Title;
    ContentItem item = post.ContentItem;
    <li class="content-item-summary">
@Html.ItemDisplayLink(title, item)
</li> } </ul>

Here's the full template code:

@using Orchard.ContentManagement;
@{
    IEnumerable<object> blogPosts =
Model.ContentItems.ContentItems; } @if (blogPosts == null || blogPosts.Count() < 1) { <p>@T("No posts.")</p> } else { <ul class="content-items"> @foreach (dynamic post in blogPosts) { string title = post.Title; ContentItem item = post.ContentItem; <li class="content-item-summary">
@Html.ItemDisplayLink(title, item)
</li> } </ul> }

And here's the result:Neat and clean

I hope this helps.

Comments

Skywalker said:

This is EXACTLY what I was trying to figure out. And now that I see it how easy it is I don't understand I didn't figure it out myself. But I guess that goes for most of the things (once you know how, it's easy).

Two questions I'm still having are:

1. Is it possible to create multiple templates ("skins") for a single Widget.

2. If question 1 resolves to true, then how do I do it?

Thanks!

# March 28, 2011 9:53 AM

Bertrand Le Roy said:

@Skywalker: sure, but what do you want to base the decision on?

# March 28, 2011 3:15 PM

Skywalker said:

It would be great to be able to base the decision on the layer and/or the zone the widget is assigned to.

For example, I have two Blogs: one blog hosts all Political articles, and the other blog hosts all Personal blogposts.

I want to render the Political blogposts in the zone named "Content" using the RecentBlogPosts widget using a custom list template (the way you described in this post). The Personal posts I want to render in the zone "AsideSecond", also using the RecentBlogPosts widget, but using another template.

To achieve that I guess I should name the two templates correctly, but I'm not sure how to name them.

Is it like:

1. Parts.Blogs.RecentBlogPosts-Content.cshtml

2. Parts.Blogs.RecentBlogPosts-AsideSecond.cshtml

?

And if I wanted to use another skin based on the current layer (like "TheHomePage"), would that be possible? What about a combination of the two: I want to use template A only on layer "Authenticated" in the zone "AsideSecond". On layer "Anonymous" I want to use the same widget, but render it using another template.

Perhaps I'm aproaching these problems from the wrong angle, but I'm still trying to grasp the essentials of Orchard, especially theming.

# March 28, 2011 4:08 PM

Bertrand Le Roy said:

The right way to do this is to create alternates for the shape, I think. I have a post about that.

# March 28, 2011 4:26 PM

Skywalker said:

Just the direction that I needed. Thanks, I will look that up!

# March 28, 2011 5:21 PM

Pedro Salgado said:

Great post Bertrand but I still have a doubt.

Is it possible to show other fields from my content type in the list?

I want my list to show subtitle (Text Field), lead (HTML Field) and picture (File Field).

If its true, how do I do it?

Thanks!

# March 29, 2011 1:17 PM

Bertrand Le Roy said:

@Pedro: sure, I would recommend you try the new Shape Tracing feature in the upcoming Orchard 1.1. The model tab will give you the syntax that you can copy and paste into your template for any field or part property. The difference here would be probably that you would apply the same path, but from the content item instead of from Model.

# March 29, 2011 4:31 PM

Bogdan said:

Hello, a great post that helped me with the view for my recent blog posts, but I seem to be encountering some difficulties trying to display another content type.

My scenario is the following : I have a list of "Service" content types, that I display in a widget in the AfterMain zone on the homepage and in a separate page linked to the main menu. I have created the view for the separate page (Content-Service.Summary.cshtml), and after reading the documentation about alternate templates, have created a Widget-AfterMain.cshtml view to change what appears on the homepage in the widget.

The problem is I cannot access the list items with Model.ContentItems.ContentItems. I know that with Model.Content I can make them appear, but I cannot dig further down than that, not event with Shape Tracing, which doesn't show me in the Model the actual Service Content Items.

I don't event know if doing the view for this in Widget-AfterMain.cshtml is appropiate, as any other future widgets, on other pages, placed in this zone, will be affected.

Can you guide me please? Thank you

# April 28, 2011 6:09 AM

Bertrand Le Roy said:

I can only guess, but you're probably not looking at the right shape. I would need to take a look at the code to be able to provide anything beyond guesses. Feel free to use the contact form.

# April 28, 2011 3:10 PM

Bogdan said:

Thanks, I've sent you the code.

# April 29, 2011 10:46 AM

esims said:

hi, i'm a noob to orchard. still trying to understand. i want to change around some things in my blog posts and your article looks like how i do it.

so, are you saying all i need to do to change the appearance is to create a file called 'Parts.Blogs.RecentBlogPosts.cshtml' and place it in my theme's views folder and that's it? i don't have to add any other code or do any compiling?

sorry for the dumb question, but thanks for your help.

only reason i'm asking is this is what i did, but i don't see any changes.

# May 16, 2011 12:45 PM

Bertrand Le Roy said:

@esims: yes, that is all you need to do but this is to change what gets displayed by the recent blog posts widget. If that's not what you want to change, you need to determine first what template is rendering what you want to change. I recommend using the Shape Tracing feature to figure that out.

# May 17, 2011 5:18 PM

JonVee said:

I've created a custom containable content type with image and text fields included as parts... (I read this may be of use later on when I try to search

based on those fields or rather part properties)..

Anyways I've got an image field and can't figure out how to display as a link to the details view.

I can't get past how the @Html.ItemDisplayLink(title, contentItem) for the title actually pulls the route.

I've tried <a href="@Model.ContentPart.Path">...</a> in the custom field view (using shape tracing),but that doesn't render anything in the href. I assume I need to tell it what the content part is somehow.

I'm also wondering if I should be creating this as a modue rather than via Orchard admin and adding content parts, fields, etc..?

Yes I am a noob and I will be laughed at ;)

# July 9, 2011 3:54 PM

Bertrand Le Roy said:

@JonVee: you might want to use Shape Tracing's Model tab to determine how to get to the data you want to display.

# July 11, 2011 5:27 PM

arpita said:

How can i display only blogs using one tag?

e.g. B2B is one tag used in page,blog etc but i want to display blog only.

# October 4, 2011 12:09 PM

Bertrand Le Roy said:

@arpita: write your own controller action, with a query on the blog post part, with a where on tags.

# October 4, 2011 4:19 PM

Brainwrecker said:

Hi Bertrand,

How can I display 2 different lists on a page? When I create a list, it is displayed as a page itself...but I want 2 lists on the same page.

# March 7, 2012 11:36 PM

Bertrand Le Roy said:

Widgets?

# March 9, 2012 6:35 PM