Search code examples
tridion

How do I pass arguments down to component (Dreamweaver) templates?


I have a page template that outputs three component presentations in a div down the bottom of the page. All three of these component presentations use the same schema and Dreamweaver component template.

I'd like to style these component presentations slightly differently based on whether they're the first component in that div, or the last - basically I'd like to add "first" and "last" CSS classes to each component presentation.

I'm trying to set "arguments" for the component presentations dynamically, in a template building block. Below is what I've got so far (doesn't work, but just to give you an idea of what I'm trying to do):

public override void Transform(Engine engine, Package package)
{
    var page = GetPage();
    var wantComponents =
        from c in page.ComponentPresentations
        where c.ComponentTemplate.Title == "Content highlight"
        select c;
    if (wantComponents.Count() > 0)
    {
        // pseudocode - won't compile!
        wantComponents.First().ComponentTemplate.Parameters["myCssClass"] = "first";
        wantComponents.Last().ComponentTemplate.Parameters["myCssClass"] = "last";
    }
    ...

In my Dreamweaver template (again, doesn't work, just to give you an idea of what I'm trying to do):

<div class="block @@Parameters.myCssClass@@">
    ...
</div>

How do I dynamically add the "first" CSS class to the first component presentation on the page, and the "last" CSS class to the last component presentation on the page?


Solution

  • Not a bad question at all George.

    If you take your divs out of the Component Template and put them into the Page Template then you don't need to pass the arguments from the Page template into the Component Template. Then setting the CSS class to the first component presentation is easy:

    <div class="<!-- TemplateBeginIf cond="TemplateRepeatIndex==0" -->myFirstCssClass<!-- TemplateEndIf -->"></div>
    

    Setting a class on the last Component Presentation is a bit more fun and there are a couple of ways this can be achieved:

    1. A custom Dreamweaver function, for example TemplateRepeatCount(). Then you can do stuff like this inside your Page Template: <!-- TemplateBeginRepeat name="Components" --><div class="<!-- TemplateBeginIf cond="TemplateRepeatIndex==TemplateRepeatCount()-1" -->lastCssClass<!-- TemplateEndIf -->">@@RenderComponentPresentation()@@</div><!-- TemplateEndRepeat -->.
    2. The other approach is to write a basic TBB that counts up the component presentations and drops the total number onto the package, and then you can compare your TemplateRepeatIndex against this number.

    Both #1 and #2 above are described in my article here: http://www.tridiondeveloper.com/more-fun-with-dreamweaver-templates-templaterepeatcount

    Finally, here is an approach more inline with specifically what you were asking where a Component Template actually looks up into the Page's scope to determine if it's the last Component Presentation in the list. It's not my favourite because it's not so easy to debug with TemplateBuilder (since when you're running through a CT you don't have a PT, hence the component presentation count doesn't exist in this scope).

    public class IsLastCP : TemplateBase
    {
        private string MY_SCHEMA = "My Component's Schema Title";
    
        public override void Transform(Engine engine, Package package)
        {
            this.Initialize(engine, package);
    
            //in the page template.
            Page page = this.GetPage();
            if (page == null)
            {
                //this TBB is being executed either in Template Builder or a dynamic component presentation.
                // so we just don't do anything.
            }
            else
            {
                IList<ComponentPresentation> cpList = page.ComponentPresentations;
    
                int cpCount = 0;
                int thisCPIndex = -1;
    
                Component thisComponent = this.GetComponent();
    
                foreach (ComponentPresentation cp in cpList)
                {
                    Component comp = cp.Component;
                    if (comp.Schema.Title == MY_SCHEMA)
                    {
                        if (comp.Id.Equals(thisComponent.Id))
                            thisCPIndex = cpCount;
                        cpCount++;
                    }
                }
    
                if (thisCPIndex == cpCount-1)
                {
                    package.PushItem("IsLastCP", package.CreateStringItem(ContentType.Text, "true"));
                }
            }
        }
    

    For this you'll need Will's famous TemplateBase class which you can get from his "Useful Building Blocks" extension available from SDLTridionWorld. Obviously you'll need to tweak the code I provided to your schema name, etc.

    Drop this TBB ahead of your Dreamweaver TBB in your Component Template then use its output like this: <!-- TemplateBeginRepeat name="IsLastCP" -->class="myLastCSSClass"<!-- TemplateEndRepeat -->

    Note: you don't need to do a TemplateBeginIf here and check explicitly for true/false on IsLastCP. If the CP in question is last, then this variable will be present in the package, and the TemplateBeginRepeat clause will enter.