Render alternative view

Topics: Customizing Orchard, Writing themes
Dec 17, 2012 at 2:27 AM
Edited Dec 17, 2012 at 2:30 AM

Hi,

I have a custom content type and it's rendered as the following for summary view

<article class="content-item @contentTypeClassName">
    <header>
        @Display(Model.Header)
        @if (Model.Meta != null) {
        <div class="metadata">
            @Display(Model.Meta)
        </div>
        }
    </header>
    @Display(Model.Content)
    @if(Model.Footer != null) {
    <footer>
        @Display(Model.Footer)
    </footer>
    }
</article>

The @Display(Model.Content) contains some numeric, enumerable and input fields. Each of them is rendered in a separate p tags. I want to render them in single table. So I found an article an article which is suggested this can be done by using some Clay wizardry to enumerate zones and then the shapes within them to find one with the specified name.

The following is the helper code

public static class ShapeHelper
{
	public static dynamic Find(IShape model, string name)
        {
            var zones = new Dictionary<string, object>();
            ((IClayBehaviorProvider)model).Behavior.GetMembers(_nullFunc, model, zones);

            foreach (var key in zones.Keys.Where(key => !key.StartsWith("_")))
            {
                var zone = zones[key] as IShape;

                if (zone == null || zone.Metadata.Type != "ContentZone")
		{
		    continue;
		}

                foreach (IShape shape in ((dynamic)zone).Items)
                {
                    if (shape.Metadata.Type == name)
		    {
		        return shape;
		    }
                }
            }

            return null;
        }

        private static readonly Func<object> _nullFunc = () => null;
}

and my view code are:

@foreach(var item in Model)
{
       @ShapeHelper.Find(item, "Parts_ZenGallery.Summary")
}

But I’m getting an error as stated below

Unable to cast object of type 'IShapeProxy274846b39fc94a98abccc141a9b19d47' to type 'ClaySharp.IClayBehaviorProvider'

Does anyone know how to resolve this error or any other suggestion to resolve my rendering issue?

Thank you
muges

Coordinator
Dec 17, 2012 at 4:09 AM

What version of Orchard are you using?

Dec 17, 2012 at 11:18 AM

I'm using version 1.6.

Coordinator
Dec 17, 2012 at 4:53 PM

Maybe there is a shape in there that doesn't implement IClayBehaviorProvider. Maybe change the helper code to do an "as" instead of a cast?

Dec 18, 2012 at 10:30 PM

I try to use as instead of a cast but it's throwing an "object reference not set to an instance of an object" error.

When I try to debug it was at the following line

((IClayBehaviorProvider)model).Behavior.GetMembers(_nullFunc, model, zones);

Is there any other way to do this? 

Coordinator
Dec 19, 2012 at 12:15 AM

Show me the code you've replaced it with. It should be something like:

var clayBehaviorProvider = model as IClayBehaviorProvider;
if (clayBehaviorProvider == null) return null;
clayBehaviorProvider.Behavior.GetMembers(_nullFunc, model, zones);

 

Dec 19, 2012 at 11:51 PM

I didn't check for null before.

However, after i implimented as above it doesn't render anything.

Coordinator
Dec 20, 2012 at 12:44 AM

Oh, that one is easy: it's because you're not calling the helper on Model like you should and like the blog post was showing.

Dec 20, 2012 at 7:05 PM
Edited Dec 20, 2012 at 7:06 PM

What do you mean?

This is how I'm calling the ShapeHelper

@Display(ShapeHelper.Find(Model, "Parts_ZenGallery"))
@Display(ShapeHelper.Find(Model, "Parts_Common_Body"))

Instead of 

@Display(Model.Content)

The ShapeHelper class looks like this now

public static class ShapeHelper
    {
        public static dynamic Find(IShape model, string name)
        {  
            var zones = new Dictionary<string, object>();
            var clayBehaviorProvider = model as IClayBehaviorProvider;

            if (clayBehaviorProvider == null)
            {
                return null;
            }

            clayBehaviorProvider.Behavior.GetMembers(_nullFunc, model, zones);
            foreach (var key in zones.Keys.Where(key => !key.StartsWith("_")))
            {
                var zone = zones[key] as IShape;
                if (zone == null ||
                    zone.Metadata.Type != "ContentZone") continue;
                foreach (IShape shape in ((dynamic)zone).Items)
                {
                    if (shape.Metadata.Type == name) return shape;
                }
            }
            return null;
        }

        private static readonly Func<object> _nullFunc = () => null;
    }

Please help me to point out, what I'm doing wrong here?

Thank you

muges

Coordinator
Dec 28, 2012 at 7:58 AM

What I mean is that in your previous post you wrote @ShapeHelper.Find(item, "Parts_ZenGallery.Summary"). Which are you using?

Dec 28, 2012 at 5:02 PM

Hi,

I'm using

@Display(ShapeHelper.Find(Model, "Parts_ZenGallery.Summary"))
@Display(ShapeHelper.Find(Model, "Parts_Common_Body"))

Thank you

muges

Coordinator
Dec 28, 2012 at 8:48 PM

from what template?

Jan 3, 2013 at 8:43 PM

Happy new year Bertrandleroy,

I'm not sure whether I get it right, but I'm using it in details template. I have tried "Parts_ZenGallery" and "Parts_ZenGallery.Summary" but both doesn't render anything.

Thank you

Jan 15, 2013 at 11:52 AM

Hi,

Any information regarding this issue?

Thank you

muges

Developer
Jan 15, 2013 at 12:04 PM

Bertrand asked from what template you're executing that code. The reason, I assume, is that we need to know what Model is. So, from which template are you executing the code?

Coordinator
Jan 15, 2013 at 5:39 PM

That helper is meant to be used in a "content" template alternate, not in a part's template. It won't work if the Model object does not have zones.

Jan 16, 2013 at 7:34 PM

Hi,

I have created custom contentype and added few fields and custom content part. One of the content part is Zen gallery. I'm trying to use this helper in the detail page so that I can render different html.

E.G.
I want the Zen gallery to display as it is and all the other fields and parts to be display in a single table below the Zen gallery. Since this helper can’t be used in this situation, what can I do to achieve this? Any suggestion?

Thank you.
muges

Coordinator
Jan 17, 2013 at 1:11 AM

What is the markup that you want to obtain?

Jan 20, 2013 at 11:35 AM

Hi, 

The current markup it's rendering as follows:

<article class="post post-page content-item property-for-rent" shape-id="0">
    <header shape-id="0">
        <h1 shape-id="1">4 bedroom end terrace house to rent</h1>
    </header>
    <p class="numeric-field price" shape-id="6">
        <span class="name" shape-id="6">Price:</span>
        <span class="value" shape-id="6">�1,300.00 (PCM)</span>
    </p>

    <p class="numeric-field numeric-field-bedrooms" shape-id="7">
        <span class="name" shape-id="7">Bedrooms:</span>
        <span class="value" shape-id="7">4</span>
    </p>

    <p class="numeric-field numeric-field-bathrooms" shape-id="8">
        <span class="name" shape-id="8">Bathrooms:</span>
        <span class="value" shape-id="8">1</span>
    </p>

    <p class="text-field text-field-furnished" shape-id="9">
        <span class="name" shape-id="9">Furnished:</span>
        <span class="value" shape-id="9">Yes</span>
    </p>    

    <p class="text-field text-field-double-glazing" shape-id="10">
        <span class="name" shape-id="10">Double Glazing:</span>
        <span class="value" shape-id="10">Yes</span>
    </p>    
</article>

I want it to render all the fields in to be rendered in a table as follows:

<article class="post post-page content-item property-for-rent" shape-id="0">
    <header shape-id="0">
        <h1 shape-id="1">4 bedroom end terrace house to rent</h1>
    </header>
    <table>
        <tr>
            <td>
                <span class="name" shape-id="6">Price:</span>
                <span class="value" shape-id="6"1,300.00 (PCM)</span>
            </td>
            <td>
                <span class="name" shape-id="7">Bedrooms:</span>
                <span class="value" shape-id="7">4</span>
            </td>
        </tr>
        <tr>
            <td>
                <span class="name" shape-id="8">Bathrooms:</span>
                <span class="value" shape-id="8">1</span>
            </td>
            <td>
                <span class="name" shape-id="9">Furnished:</span>
                <span class="value" shape-id="9">Yes</span>
            </td>
        </tr>
        <tr>
            <td>
                <span class="name" shape-id="10">Double Glazing:</span>
                <span class="value" shape-id="10">Yes</span>
            </td>
        </tr>
    </table>
</article>

How can I do this?

Thank you

muges

Coordinator
Jan 20, 2013 at 8:50 PM

Then, override the content template, not the zen gallery part's template, and use the helper to render the zen template and the field templates.