How can I prevent a zone being rendered when its fields are empty?

Topics: Customizing Orchard
Oct 19, 2014 at 3:03 AM
In my Orchard solution I've:
  • added two custom HTML fields (HTML) to the Page content type
  • configured the placement for these fields in my placement.info
  <Match ContentType="Page">
    <Place Fields_Common_Text-CustomField1="/AsideSecond:1" />
    <Place Fields_Common_Text-CustomField2="/AsideFirst:1" />
  </Match>
  • In my layout.cshtml I have the following code
        @if (Model.AsideFirst != null)
        {
            <aside id="aside-first">
                @Zone(Model.AsideFirst)
            </aside>
        }

        @if (Model.AsideSecond != null)
        {
            <aside id="aside-second">
                @Zone(Model.AsideSecond) 
            </aside>
        }
This allows content editors to specify content (HTML) to appear per page in the first and second zones without needing a developer to configure layer rules and create widgets.

The problem is that the zones are always rendered, even when the custom fields are empty.

Does anyone know how I can prevent this?
Oct 19, 2014 at 4:30 AM
Edited Oct 19, 2014 at 4:56 AM
This feels like (EDIT: is) a hack, but I managed to get around the issue with this code in my Layout.cshtml template
    // Remove empty items from AsideFirst
    if (Model.AsideFirst.Items.Count == 1)
    {
        if (Model.AsideFirst.Items[0] is IShape && (bool)Model.AsideFirst.Items[0].Name.StartsWith("CustomField"))
        {
            if (String.IsNullOrEmpty(Model.AsideFirst.Items[0].Value.ToString()))
            {
                Model.AsideFirst = null;
            }
        }
    }
Developer
Oct 19, 2014 at 4:30 AM
The problem is that the AsideSecond zone will now always contain a Fields_Common_Text shape, regardless of the text field itself having a value.
Only if a zone does not contain shapes, will it be equal to null.
You could work around this by finding your text field shape before rendering the zone, and then only render the zone if the text field contains a value.
However, this is a very brittle implementation, because if you add other shapes to that zone, you do want to render it, regardless of the text field having a value.

A somewhat better workaround might be to implement your own TextFieldDriver that suppresses the default one, where you only return a Fields_Common_Text shape if the text field has a non-empty value.

I have run into this scenario once before myself, and I wished there were a way to tell a shape to remove itself from its containing shape, which I could for example do from a shape table provider, from where I would check if a text field has a value or not. If the value is empty, I would then simply instruct the shape to remove itself from its parent zone holding shape. Maybe someday my wish will be fulfilled. Until then the field driver approach might be a way to go. Or maybe you can try the new Layouts module, so that you don't have to attach two custom fields to your type (or you could, but then you would still use the canvas to place the field elements).
Oct 19, 2014 at 5:04 AM
Thanks for the fast response, sfmskywalker.

"this is a very brittle implementation, because if you add other shapes to that zone, you do want to render it, regardless of the text field having a value".

It's definitely a hack, but it's working for now... The code above checks for the name of the field, and is only called when there's a single item in the zone.

Cheers!