More fun with Dreamweaver Templates – TemplateRepeatCount

Quite a while back (in ’09’ I think) I replied to a thread on the sdltridionworld forum regaring how to get the total count of your elements when doing a TemplateBeginRepeat inside a DWT.

For example when you have a special css class that needs to be applied to the last item in the list.

<ul>
<li><a href="/contact/">Contact Us</a></li>
<li><a href="/sitemap/">Site Map</a></li>
<li class="last"><a href="/terms-of-use/"></a></li>
</ul>

An intuitive approach is to have a function or a variable that provides the count so that you can use syntax like this:

<ul>
<!– TemplateBeginRepeat name="Component.LinkList" –>
<li><a href="@@MyUrlField@@">@@MyUrlText@@</a></li>

<!– TemplateBeginIf cond="TemplateRepeatIndex == TemplateRepeatCount()-1 –>
<li class="last"><a href="@@MyUrlField@@">@@MyUrlText@@</a></li>

<!– TemplateEndIf –>
<!– TemplateEndRepeat –>
</ul>

Here is the code for it:

[TemplateCallable]
public string TemplateRepeatCount(string componentTcmId, string fieldName)
{
    Logger.Info("Start of Count");

    IdentifiableObject item = _engine.GetObject(componentTcmId);
    int count = 0;
    if (item.GetType().Name == "Component")
    {
        Component c = item as Component;
        //find the field collection and get the count
        ItemFields fields = new ItemFields(c.Content, c.Schema);

        Logger.Debug("Got component itemfields");
        if (fields.Contains(fieldName))
        {
            Logger.Debug("Found item field: " + fieldName);

            ItemField field = fields[fieldName];
            Logger.Debug("Field type: " + field.GetType().Name);

            switch (field.GetType().Name)
            {
                case "ComponentLinkField":
                {
                    Logger.Debug("Field is ComponentLinkField");
                    ComponentLinkField typedField = field as ComponentLinkField;
                    count = typedField.Values!=null?typedField.Values.Count:0;
                }
                break;

                case "EmbeddedSchemaField":
                {
                    Logger.Debug("Field is EmbeddedSchemaField");
                    EmbeddedSchemaField typedField = field as EmbeddedSchemaField;
                    count = typedField.Values != null ? typedField.Values.Count : 0;
                }
                break;

                case "SingleLineTextField":
                case "ExternalLinkField":
                case "XhtmlField":
                case "MultiLineTextField":
                {
                    Logger.Debug("Field is TextField");
                    TextField typedField = field as TextField;
                    count = typedField.Values != null ? typedField.Values.Count : 0;
                }
                break;

                case "DateField":
                {
                    Logger.Debug("Field is DateField");
                    DateField typedField = field as DateField;
                    count = typedField.Values != null ? typedField.Values.Count : 0;
                }
                break;

                case "NumberField":
                {
                    Logger.Debug("Field is NumberField");
                    NumberField typedField = field as NumberField;
                    count = typedField.Values != null ? typedField.Values.Count : 0;
                }
                break;

                case "KeywordField":
                {
                    Logger.Debug("Field is KeywordField");
                    KeywordField typedField = field as KeywordField;
                    count = typedField.Values != null ? typedField.Values.Count : 0;
                }
                break;
            }
        }
    }

    return count.ToString();
}

Though, here is another approach which I used one late night in the office wanting to finish a template.  It was past my sys admin’s office time, so I couldn’t ask him to deploy a new Custom Functions DLL to the CM server’s GAC/bin, but I just had to get the template done by end of day – I was in the zone.  Besides, I couldn’t let it linger the next day.  

So here is a quick C# fragment that should be used in sequence after Will Price’s “Get Linked Components” extension (just Google it if you don’t know.  It’s the best thing since the combustion engine/sliced bread/eh…SDL Tridion CMS).

Anyway, just drop this C# Fragment in after “Get Linked Components”:

<%@ Import Namespace="Tridion.ContentManager.ContentManagement.Fields"%>
<%@ Import Namespace="System.Collections.Generic"%>

/// This TBB loops through all the items in the package and for any items which are Component Arrays
/// adds a new package item with the array entry count.  This is useful when a Dreamweaver TBB needs to know
/// the total count of components or when needing to know if you're on the last component.

List<KeyValuePair<string, Item>> extractedComponentLists = new List<KeyValuePair<string, Item>>();
foreach (KeyValuePair<string, Item> kvp in package.GetEntries())
{
    if (kvp.Value.ContentType == ContentType.ComponentArray)
    {
        //get count
        extractedComponentLists.Add(kvp);
    }
}

// This code has to be kept in a separate loop since you can't modify the package.GetEntries collection while looping through it.
foreach (KeyValuePair<string, Item> kvp in extractedComponentLists)
{
    IComponentPresentationList linkCollectionCPList = ComponentPresentationList.FromXml(kvp.Value.GetAsString());
    int componentCount = linkCollectionCPList.Count;
    package.PushItem(kvp.Key + "Count", package.CreateStringItem(ContentType.Number, componentCount.ToString()));
}

After this TBB runs, you’ll get a new entry on the package with the count for each “Tridion/Component[]” item type that “Get Linked Components” fetches.  So if we had a multi-value component link field in the component called “LinkList”, then “Get Linked Components” should fetch a component array and call it after your field name – something like “LinkList”.  Then after this DWT a new entry will appear called “LinkListCount”.

Use it like this in your DWT:

<ul>
<!-- TemplateBeginRepeat name="Component.LinkList" -->
<li><a href="@@MyUrlField@@">@@MyUrlText@@</a>
<li><!-- TemplateBeginIf cond="TemplateRepeatIndex == LinkListCount-1 --> 
<li><a href="@@MyUrlField@@">@@MyUrlText@@</a>
<li><!-- TemplateEndIf -->
<!-- TemplateEndRepeat -->
</ul>

2 thoughts on “More fun with Dreamweaver Templates – TemplateRepeatCount

  1. When i use this TemplateRepeatCount() and when i try to run my component in Template builder , its throwing an error saying
    “JScriptException: Expression ‘TemplateRepeatCount()’ had error ‘Variable ‘TemplateRepeatCount’ has not been declared’

    Is this an inbuilt function or do i have to use any c# comp to use this ?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>