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>