3

In our DD4T project, we have a need to pass certain contextual information from the Page view to the Component Presentation view - specifically, there are classes nested within the Component Presentation view that must differ according to the Page Template on which the CT is used (in such a way that these containers can't be moved to the PT view). Unfortunately, changing the markup is not an option as this is the product of a fairly complex responsive grid system.

The way we're handling this at the minute works but is fairly ugly - grabbing the Page Template from the IComponentPresentation and switching out the CSS class accordingly within the CP view. As you can imagine, this is shaping up to be a maintenance nightmare as the need to reuse CTs on various Page Templates emerges.

What we need is essentially the routeValues parameter of ChildActionExtensions.Action, so I could do something like this:

@Html.RenderComponentPresentations(new { SomeParameter = "SomeValue" })

Then I could just pass my class into the CP, for example. However, I can't see anywhere to pass additional routevalues in via the current RenderComponentPresentations helper, nor anything on the IComponentPresentationRenderer interface that would let me write my own helper and/or custom renderer.

So, I'm a bit stuck. Short of doing something funky like adding the classes into the ViewBag in the Page view and then pulling them off the HtmlHelper in a custom CP renderer - or reimplementing a load of framework logic to call the CP actions directly - I can't see an elegant solution.

Has anyone managed to solve this issue before? It seems as though IComponentPresentationRender.RenderComponentPresentation could use an overload that accepts a parameter for additional route values.

1 Answer 1

5

I don't see why storing and fetching context data is considered 'funky' as I always thought that passing data only know at request time is what the ViewBag is for. Any other data should indeed be passed in the model, which is passed to the Component Presentation renderer. In any case, I use a mechanism like this, which may be considered pretty ugly, but works like charm:

public static dynamic GetParentPageViewBag(this HtmlHelper helper, ViewContext viewContext)
{
    if (viewContext.ParentActionViewContext.Controller == null)
    {
        throw new Exception("Use this only on Tridion Component Views");
    }
    if (viewContext.ParentActionViewContext.Controller is DD4T.PageController)
    {
        if (viewContext.ParentActionViewContext.Controller.ViewBag.Page != null)
            return viewContext.ParentActionViewContext.Controller.ViewBag;
    }
    if (viewContext.ParentActionViewContext.Controller is DD4T.ComponentController)
    {
        if (viewContext.ParentActionViewContext.ParentActionViewContext != null &&
            viewContext.ParentActionViewContext.ParentActionViewContext.Controller is DD4T.PageController)
        {
            if (viewContext.ParentActionViewContext.ParentActionViewContext.Controller.ViewBag.Page != null)
            {
                return viewContext.ParentActionViewContext.ParentActionViewContext.Controller.ViewBag;
            }
        }                 
    }
    throw new Exception("Use this only on Tridion Component Views rendered with the PageController");
}

// Usage in a Comoonent View
var pageViewBag = Html.GetParentPageViewBag(ViewContext);
MyNeededParentData data = pageViewBag.MyNeededParentData;

If you want to go the RouteValueDictionary way, which is also perfectly valid, then you can adapt the standard RenderComponentPresentations method as overload and pass in extra variables.

9
  • To be honest, I consider use of ViewBag at all to be something to be generally avoided. However, the reason I consider this particular use of ViewBag "funky" is that its intended use is as a way to pass data to a view and back again, not generally to be assigned to explicitly in the view and picked up in a child action, which is a fairly hacky workaround to something that should essentially just be an argument in a method call.
    – Ant P
    Commented Mar 21, 2014 at 11:37
  • Your latter suggestion is what I really want but unfortunately there's no way to do this without bypassing the framework as - even if I overload the helper - there's no IComponentPresentationRenderer overload to accommodate it.
    – Ant P
    Commented Mar 21, 2014 at 11:38
  • I fully agree with that. I was looking for an ActionResult method where I also do exactly what you describe. In any case, I said it's possible, but not recommended per se. If you can use a proper model, then do so. :)
    – Raimond
    Commented Mar 21, 2014 at 11:39
  • 1
    But that involves bypassing the IComponentPresentationRender interface and calling the CP controller action explicitly, which, as I mentioned in my question, I want to avoid as it's an abuse of the framework that kills the isolation of the action routing logic. There's no way to adhere to the framework and pass the variables as routeValues because there's no way of passing routeValues and still using the existing interface: code.google.com/p/dynamic-delivery-4-tridion/source/browse/…
    – Ant P
    Commented Mar 21, 2014 at 11:58
  • 1
    Well, if don't want to do that, you should be able to extend the component model itself, as others have also done. That way you can keep using the interface.
    – Raimond
    Commented Mar 21, 2014 at 12:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.