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.

17 Comments

  • 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!

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

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

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

  • 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!

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

  • 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

  • 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.

  • Thanks, I've sent you the code.

  • 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.

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

  • 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 ... 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 ;)

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

  • 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.

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

  • 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.

  • Widgets?

Comments have been disabled for this content.