Number of Items in Model.ContentItems

Topics: General, Writing themes
May 13, 2013 at 9:59 AM
Greetings All,

I'm using the shapes layout from the projection layout module, and having trouble in determining the total number of shapes in the list. An earlier 'blog post shows an example something like this:

var list = Model.ContentItems;
var items = list.Items;
var count = items.Count;

and I've put that in my templet, however it fails with an error "Object does not contain a definition for Items".

Anyone know how to obtain the total number of items in Model.ContentItems?
May 13, 2013 at 4:01 PM
Which shape have you created an alternate of?
  1. Create an alternate for the List shape for the projection -> Create a new file ->
    ---> ~/Themes/{mytheme}/Views/List-ProjectionWidget.cshtml <- projection widget
    ---> ~/Themes/{mytheme}/Views/List-ProjectionPage.cshtml <- projection page
  2. Add to the view some markup to describe the row
@model dynamic
    List<object> items = Model.Items;
    var itemCount = 0;

<div data-items-count="@items.Count">
    @foreach (var item in items)
        <div data-item-number="@(++itemCount)">
If you already have something very similar then I will try to help again.
May 14, 2013 at 3:10 AM
Thanks. I created an alternate of the projection page, using the 'shape' layout from the projection layout extension module. When I look at the page with shape tracing, I can see that Items doesn't contain any objects. The objects that I am displaying are in ContentItems, and I can see the list and its contents there. Unfortunately the type of ContentItems is WhereSelectListIterator<LayoutComponentResult, ContentItem>, which doesn't lend itself well to manipulation. There's a 'buildShapes' function that will return a IEnumerable<Objects>, but after searching it seems there's no good way to obtain the count from IEnumerable without iterating over it first.

I can do that and make it work, but I'm wondering if there's either an easier way or if I'm missing something here. It seems rather inefficient to iterate over the list just to determine the total number, and I think this would be common enough that there's an easier way provided somewhere.
May 14, 2013 at 12:08 PM
nunez wrote:
Thanks. I created an alternate of the projection page, using the 'shape' layout from the projection layout extension module.
Is this the module you are using? - Projection Layouts - Version: 1.0
If so then I haven't used it yet (or noticed it existed). I'll give it the quick spin to see if I can find anything useful from it.
I have gone as far as building my own driver for this kind of thing and had the driver tell the shape the extra things its needed.
May 14, 2013 at 12:29 PM
Shape layout:
            string shapeType = context.State.ShapeType;

            dynamic shape = ((IShapeFactory) Shape).Create(shapeType);
            shape.ContentItems = layoutComponentResults.Select(x => x.ContentItem);
            shape.BuildShapes= (Func<IEnumerable<dynamic>>) (() => context.LayoutRecord.Display == (int)LayoutRecord.Displays.Content
                   ? layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType))
                   : layoutComponentResults.Select(x => x.Properties));

            return shape;
it wound not be a costly execution to call count on ContentItems.

Why not use the Html List layout? That provides the scenario I implemented in my first post and gives you the properties you were looking for.

Now I'm curious to see what the layout does.
May 14, 2013 at 2:46 PM
matt4446 wrote:
Why not use the Html List layout? That provides the scenario I implemented in my first post and gives you the properties you were looking for.
Alternatively to get the same result with the 'shape' layout for the projection:
    var buildShapes = Model.BuildShapes;

    IEnumerable<object> items = buildShapes(); 
    List<object> shapes = items.ToList(); 
    var itemCount = 0;

<div data-items-count="@shapes.Count">
@foreach (dynamic shape in shapes)
    <div data-item-number="@(++itemCount)" class="row">  
Alternatively you could write your own Layout provider quite easily looking at it and provide the totals directly. Changing this part:
public dynamic RenderLayout(LayoutContext context, IEnumerable<LayoutComponentResult> layoutComponentResults) {
            string containerTag = context.State.ContainerTag;
            string containerId = context.State.ContainerId;
            string containerClass = context.State.ContainerClass;

            string itemTag = context.State.ItemTag;
            string itemClass = context.State.ItemClass;

            string prepend = context.State.Prepend;
            string append = context.State.Append;
            string separator = context.State.Separator;

            dynamic[] shapes =
               context.LayoutRecord.Display == (int)LayoutRecord.Displays.Content
                   ? layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType)).ToArray()
                   : layoutComponentResults.Select(x => x.Properties).ToArray();

            return Shape.Raw(
                Id: containerId, 
                Items: shapes, 
                Count: shapes.Length,
                Tag: containerTag,
                Classes: new [] { containerClass },
                ItemTag: itemTag,
                ItemClasses: new [] { itemClass },
                Prepend: prepend,
                Append: append,
                Separator: separator
Next question:
Do you need to know the amount in the list or the amount in the database?
May 15, 2013 at 12:15 AM
Ah, thanks. Multiple solutions are always good. I'm only looking at the number in the list because I know the number will be few, and the code at the top of the example does that. I don't know why I didn't hit upon that incantation. Now I'll circle back and implement the other solutions as exercises and exploration.
May 15, 2013 at 1:28 PM
It hadn't even dawned on me that creating a New Layout type for projections could be a interesting way to go. So this has helped me out too. ;-)
Feb 18 at 7:19 PM
Model.ContentItem is always empty for me. Also Model.BuildShapes returns empty list. But i can see content items in preview. My query must select all pages.