0
votes

I am trying to conditionally suppress a widget from its driver. I basically have logic that if met, should display the widget and if not, should suppress it. The widget loads properties from the current page content item, and based on some properties should display or hide. I've got all the logic working, the only part left is suppressing the actual output.

I've tried returning null from the driver, however this simply outputs an empty widget (with its wrapper). How do I completely remove the widget from view?

Finally, the zone that this widget is placed in should suppress if none of the conditional widgets display.

Is this type of flexibility possible in Orchard? Preferably from my custom module not my theme, I'm trying to separate functionality from styling.

EDIT:

Here is the context of my situation and what I am trying to accomplish. I'm sure there is a much cleaner way to do this within Orchard than how I have naively designed it the first go-around: My client's copywriters tag pages as they see fit (using the Tags module/part). I have created 2 custom content types, "Testimonials" and "Offers", both with tags themselves among other properties [these are managed by a different team of copywriters].

On most "inner pages" of the website (I'm using a layer to determine the appropriate pages), the page's sidebar gets a "Testimonial" widget and a "Offer" widget. These widgets both operate the same, although independently of each other:

They grab the tags of the current page, then pull a random [Testimonial|Offer] that has any matching tags as well. There are 4 cases that can happen given any inner page: a testimonial is displayed and the offer is hidden (testimonial tag matched, offer tag didn't), the testimonial is hidden and the offer is displayed, both the testimonial and offer displays, and finally neither displays. The first 3 use cases are working great, the 4th is what I'm having difficulty with, as the sidebar [zone] still displays even if both widgets do not (returning null from their respective drivers).

2
That's exactly what layers are doing. Create a layer, throw your rule for displaying or hiding the widget in there, done.Bertrand Le Roy
I cannot include the logic in the layer, the logic for displaying is in the widget (based on properties of the current page it is sitting on). This is all working (meaning the widgets are correctly executing against the logic and if not met, are correctly "hiding" (returning null from the driver). A layer may have multiple "conditional" widgets. It should still show if 1 widget is shown/active, but collapse if all widget children do not display. For further clarification,MikeAtCodeSmart
Why couldn't you include the logic in the layer rule? This is exactly what layers have been designed for.Bertrand Le Roy
Layer's are great when the logic scope is PAGE wide. In my circumstance, the logic is scoped to the widget, not the page. My "sidebar" has 2 widgets, which operate independent of each other. 1 widget does a lookup of the tags of the displaying page and displays a random "testimonial" (custom part/type) with the same tags. Similarly, the 2nd widget does a lookup of the page tags and displays a random "offer" (another custom part/type) with the same tags.MikeAtCodeSmart
Ran out of characters... On some pages, there may only be a matching "testimonial" widget, on other pages, there may only be a matching "offer" widget, on another subset of pages there may be both the testimonial and offer widget, and finally on others there may be no matching widgets [this is the edge case my question is about]. I don't know on what pages which combination is going to display, so I cannot create layers to handle this. Everything is working except for when the page has no matching testimonial or offer widget. I get a "blank" sidebar zone, how can i mitigate this?MikeAtCodeSmart

2 Answers

2
votes

A bit of context about widgets: widgets are supposed to be pieces of contents that are visible on some or all pages of the site, and that provide information that is not directly related to the main content item on the page (if there is such a thing).

As a consequence, what you are describing should not be implemented as widgets (all that you had to do to make it work attests to that further), because they are really part of the content item. Instead, you should have implemented a part or a field. You can then simply place the shape for this part of field, using placement, by specifying a top-level zone: <place the_shape_name="/the_zone_where_you_want_it:1"/>

0
votes

Unfortunately I've had to use a bit of a hack so that I could move on with the project as I'm under an aggressive deadline, but if there is a better method and/or solution I'll test as I get the chance and mark as the answer.

To get it to work, I overwrote the Widget.Wrapper.cshtml file within my theme. There, I assigned a variable to the Display(Model.Child) call, and if the result is an empty string simply return. This removes any empty widget wrapping tags. (I personally feel Orchard should behave this way by default):

var child = Display(Model.Child);

// -- NOTE: shape tracing breaks this logic!
if (string.IsNullOrWhiteSpace(child.ToString())) {
    return;
}

Then simply replace the @Display(Model.Child) between the header and footer with @(child)

I then added the following method to my Layout.cshtml file.

Func<dynamic, IHtmlString> CollapsableZone = x =>
{
    var display = Display(x);
    string zoneName = x.ZoneName;
    if (string.Equals(display.ToString(), string.Format("<div class=\"zone zone-{0}\"></div>", zoneName.HtmlClassify()), StringComparison.CurrentCultureIgnoreCase))
    {
        return new HtmlString(string.Empty);
    }
    return display;
};

Simple function that assigns the display call to a variable, checks if it is an empty zone tag, and returns. I then create variables for each zone assigned to the value of the function above. I replace all the @if (Model.ZoneName != null) with @if (!string.IsNullOrWhiteSpace(zoneVariable)), and replace the calls to @Zone(Model.ZoneName) with @(zoneVariable).

This is working for the time being. It is quite a hack and brittle solution but I've had to move on to other things.