Projection Layout: Table

Topics: Customizing Orchard, Writing modules
Oct 24, 2012 at 4:28 PM
Edited Oct 24, 2012 at 4:31 PM

I'm hoping someone has already done this and can help. I have a query set up that displays a content type to my users and filters by date. The way I want to lay it out is a classic table format like this:

Date Name Department
somedate somename somedept
somedate somename somedept
somedate somename somedept

(Table isnt rendering right in here, appears the <td> isn't getting the border="1" or something. You should see what I am wanting to do.)

When I choose my layout I only have two options: grid and html list. I have tried using Grid with 3 columns (in horizontal mode), but it groups each return together into one single block, instead of separating the data like I want. It surprises me that this isn't an option native to the module. Does anyone have a working solution to this? Any help would be welcomed as well.

Developer
Oct 24, 2012 at 5:50 PM

The Grid is not made for this, because it displays the content itself in a cell of a table.

 

We started a module and tried to make this layout provider : http://contribprojections.codeplex.com/ 

I wanted to develop it for 1.5 but this is difficult to finish it.

The hardest problem is to find a way to specify the Column Names and the corresponding parts or fields.

You can vote for the feature if you want : http://orchard.codeplex.com/workitem/18295

Oct 24, 2012 at 7:24 PM

Voted for it. Yeah, I'm just not a programmer so I am kind of at the mercy of the community and what they determine as important features for release.

Nov 20, 2012 at 10:54 PM

Anyone else with any suggestions?

Developer
Nov 21, 2012 at 1:54 AM

I did something similar a while ago, although the number of columns is hard-coded. I can paste the code here so you can tweak it to your needs. Or even better: make the number of columns configurable or dynamic :)

Developer
Nov 21, 2012 at 2:00 AM

Add the following two files to your theme or module (perhaps in a directory called Providers/Layouts):

Providers/Layouts/TableLayout.cs:

public class TableLayout : ILayoutProvider {
                private readonly IContentManager _contentManager;
                protected dynamic Shape { get; set; }

                public TableLayout(IShapeFactory shapeFactory, IContentManager contentManager) {
                        _contentManager = contentManager;
                        Shape = shapeFactory;
                        T = NullLocalizer.Instance;
                }

                public Localizer T { get; set; }

                public void Describe(DescribeLayoutContext describe) {
                        describe.For("Html", T("Html"),T("Html Layouts"))
                                .Element("Table", T("Table"), T("Organizes content items in a table."),
                                        DisplayLayout,
                                        RenderLayout,
                                        "TableLayout"
                                );
                }

                public LocalizedString DisplayLayout(LayoutContext context) {
                        return T("4 columns table");
                }

                public dynamic RenderLayout(LayoutContext context, IEnumerable<LayoutComponentResult> layoutComponentResults) {
                        var name = context.State.Name;
                        var shapes = layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType));
                        return Shape.Table(Items: shapes, Name: name);
                }
        }

Providers/Layouts/TableLayoutForms.cs:

public class TableLayoutForms : IFormProvider {
        protected dynamic Shape { get; set; }
        public Localizer T { get; set; }

        public TableLayoutForms(
            IShapeFactory shapeFactory) {
            Shape = shapeFactory;
            T = NullLocalizer.Instance;
        }

        public void Describe(DescribeContext context) {
            Func<IShapeFactory, object> form =
                shape => {

                    var f = Shape.Form(
                        Id: "TableLayout",
                        _Options: Shape.Fieldset(
                            Title: T("Options"),
                            
                            _Name: Shape.TextBox(
                                Id: "name", Name: "Name",
                                Title: T("The name for this layout. Used for alternates"),
                                Description: T("The name for this layout. Used for alternates"),
                                Classes: new[] { "small-text", "tokenized" }
                                )
                            )
                        );

                    return f;
                };

            context.Form("TableLayout", form);
        }
    }

Sample view:

Views/Table-Persons.cshtml

@{
        var items = Model.Items;
        var r = 0;
}
<div class="projection-table-layout">
        <h2>@Layout.Title</h2>
        <table class="projection">
                <thead>
                        <tr>
                                <td>Name / Title</td>
                                <td>Email Address</td>
                                <td>Phone</td>
                                <td>Room</td>
                        </tr>
                </thead>
                <tbody>
                        @foreach (var item in items) {
                                var even = r++%2 == 0;
                                var rowClass = even ? "even" : "uneven";
                                var personPart = item.ContentItem.PersonPart;
                                <tr class="@rowClass">
                                        <td>
                                                <div>@string.Format("{1}, {0}", @personPart.FirstName.Value, @personPart.LastName.Value)</div>
                                                <div class="secundary">@personPart.Title.Value</div>
                                        </td>
                                        <td>
                                                @if (!string.IsNullOrWhiteSpace(@personPart.EmailAddress.Value)) {
                                                        <a href="mailto:@personPart.EmailAddress.Value">@personPart.EmailAddress.Value</a>
                                                }
                                        </td>
                                        <td>@personPart.Phone.Value</td>
                                        <td>@personPart.Room.Value</td>
                                </tr>
                        }
                </tbody>
        </table>
</div>

 

Nov 23, 2012 at 4:15 PM
Edited Nov 23, 2012 at 4:16 PM

Thanks for the information and the code. I did what you suggested by placing the following files into <sitedirectory>\modules\orchard.projections\providers\layouts

 

using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Projections.Descriptors.Layout;
using Orchard.Projections.Models;
using Orchard.Projections.Services;

namespace Orchard.Projections.Providers.Layouts {
    public class TableLayout : ILayoutProvider {
                private readonly IContentManager _contentManager;
                protected dynamic Shape { get; set; }

                public TableLayout(IShapeFactory shapeFactory, IContentManager contentManager) {
                        _contentManager = contentManager;
                        Shape = shapeFactory;
                        T = NullLocalizer.Instance;
                }

                public Localizer T { get; set; }

                public void Describe(DescribeLayoutContext describe) {
                        describe.For("Html", T("Html"),T("Html Layouts"))
                                .Element("Table", T("Table"), T("Organizes content items in a table."),
                                        DisplayLayout,
                                        RenderLayout,
                                        "TableLayout"
                                );
                }

                public LocalizedString DisplayLayout(LayoutContext context) {
                        return T("4 columns table");
                }

                public dynamic RenderLayout(LayoutContext context, IEnumerable<LayoutComponentResult> layoutComponentResults) {
                        var name = context.State.Name;
                        var shapes = layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType));
                        return Shape.Table(Items: shapes, Name: name);
                }
        }
}

 

and

using System;
using Orchard.DisplayManagement;
using Orchard.Forms.Services;
using Orchard.Localization;

namespace Orchard.Projections.Providers.Layouts {

    public class TableLayoutForms : IFormProvider {
        protected dynamic Shape { get; set; }
        public Localizer T { get; set; }

        public TableLayoutForms(
            IShapeFactory shapeFactory) {
            Shape = shapeFactory;
            T = NullLocalizer.Instance;
        }

        public void Describe(DescribeContext context) {
            Func<IShapeFactory, object> form =
                shape => {

                    var f = Shape.Form(
                        Id: "TableLayout",
                        _Options: Shape.Fieldset(
                            Title: T("Options"),
                            
                            _Name: Shape.TextBox(
                                Id: "name", Name: "Name",
                                Title: T("The name for this layout. Used for alternates"),
                                Description: T("The name for this layout. Used for alternates"),
                                Classes: new[] { "small-text", "tokenized" }
                                )
                            )
                        );

                    return f;
                };

            context.Form("TableLayout", form);
        }
    }

}

Unfortunately, I do not see the layout option when I go to add a layout to my projection. I still only see HTML List and Grid listed. Is there something else that I have to do?

Nov 26, 2012 at 6:37 AM

Disable then enable the projections module.  Had the same issue... very frustrating :)

Nov 26, 2012 at 6:48 AM

Is the provided sample view an alternate template for a projection called Persons, in this case, and if so is this put in the currently used Theme Views folder? 

I apologize for the stupid question, been using this for only about 3 days now...

Coordinator
Nov 26, 2012 at 8:29 AM

As Sipke said, those can be in a theme or in a module, it's your choice. If in a theme, don't forget to include a csproj file in order for the cs files to get compiled.

Nov 26, 2012 at 5:31 PM

The reason I ask is I saw the Prefix of "Table_" on the sample alternate view and didn't realize I could create an alternate based on a layout set for the Projection.  I was looking through the documentation at http://docs.orchardproject.net/Documentation/Alternates and couldn't really see how "Table_" applied.  Does this mean "Grid_" would work also?

Nov 26, 2012 at 6:47 PM
bhillbun wrote:

Disable then enable the projections module.  Had the same issue... very frustrating :)

Still not working for me for some reason. Only see Grid and HTML List.

Dec 3, 2012 at 6:39 PM
bertrandleroy wrote:

As Sipke said, those can be in a theme or in a module, it's your choice. If in a theme, don't forget to include a csproj file in order for the cs files to get compiled.

I added the two .cs files to the Orchard.Projections.csproj file, so it should be compiled. Other than the two .cs files in the Orchard.Projections\Providers\Layouts folder, is there something I have to do to get the additional layout to show?

Coordinator
Dec 3, 2012 at 6:45 PM

Make your own module, don't modify core modules unless you are preparing a patch that you are going to contribute. Did you watch this? http://www.youtube.com/watch?v=Ka55wTTXZg8&list=UUIo5Bf9vIjfkzRRFKaT_G6Q&index=4&feature=plcp It shows how to add your own layout to projections.

Dec 3, 2012 at 6:52 PM

Exactly what I needed. Thanks!