A87D320B838E48D8A2E9D2AEC5AEC1E5
  • Thomas Pollinger
  • 19.07.2019
  • DE

RenderTags: Dynamische Anchor und Container

Man stößt im Projektbau immer wieder auf dynamische Elemente wie z.B. Anchor oder Container. Wenn man dann versucht mit den aktuellen Bordmitteln aus der Kategorie Template Rendering (RenderTags) diese Elemente auszulesen, klappt das nicht so wie man gerne möchte. Ist das wirklich so? Gibt es denn keine Möglichkeit mit dem Template Rendering an die Inhalte der dynamischen Elemente zu kommen? 

In diesem Artikel möchte ich meine Erkenntnisse für den Zugriff auf dynamische Elemente per Template Rendering teilen.
 

Dynamische Elemente - was ist das?

Es gibt im Management Server nur zwei Elementtypen, welche die Möglichkeit besitzen dynamisch zu werden. Hier mal die Beschreibung aus der Online-Hilfe:

Dynamisches Element: Die Anzahl eines dynamischen Elements lässt sich über die Projektstruktur verwalten oder in SmartEdit erweitern bzw. verringern. Die Eigenschaft Dynamisches Element, die man einem Element zuweist, macht die dynamische Erweiterung nur in der Projektstruktur des SmartTree sichtbar. Um die dynamische Erweiterung eines dynamischen Elements auch im SmartEdit-Modus sichtbar zu machen, verwenden Sie im Template Editor zusätzlich die Blockmarkierung Dynamisch. Soll der das dynamische Element umgebende Code ebenfalls mit dem Element erweiterbar sein, müssen Sie den Code im Template Editor mit der Blockmarkierung Dynamisch kennzeichnen. Dynamische Anchor eignen sich besonders für die Erstellung von Menüleisten, bei denen die Anzahl der Menüpunkte zum Zeitpunkt der Erstellung des Templates noch nicht feststeht.
 

Zugriff per Template Rendering

Als erstes legt man eine Content-Klasse mit dynamischen Elementen an:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Management Server</title>
  </head>
  <body>
    <!IoRangeDynLink><%anchorDyn%><!/IoRangeDynLink>
    <!IoRangeDynLink><%containerDyn%><!/IoRangeDynLink>
  </body>
</html>

In diesem Beispiel eine dynamischen Achor und eine dynamischen Container.

Nun erstellt man eine Instanz und erzeugt weitere dynamische Elemente innerhalb der Projektstruktur:

Als nächstes legt man an den jeweiligen Elementen noch weitere Seiten an, damit man auch was zum auslesen hat:

Im nächsten Schritt erweitert man nun die Content-Klasse um die Abfrage der dynamischen Elemente per Template-Rendering:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Management Server</title>
  </head>
  <body>
    <!IoRangeDynLink><%anchorDyn%><!/IoRangeDynLink>
    <!IoRangeDynLink><%containerDyn%><!/IoRangeDynLink>
    <hr/>
    <reddot:cms>
        <foreach itemname="objectPageElement" object="Context:CurrentPage.Elements">
            <output type="object" object="Store:Get(String:objectPageElement).Name" />
            <output type="object" object="Escape:Br" />
        </foreach>
    </reddot:cms>
  </body>
</html>

Mit der Seitenvorschau bekommen wir dann folgendes geliefert:

Oups, da sind ja plötzlich die dynamischen Elemente ;)

Nun benennen wir die Elemente individuell um, damit wir sehen welches Element in der Liste welches ist:

Jetzt nochmals eine Seitenvorschau:

Nun erkennt man den Unterschied, warum ein:

<%!! Context:CurrentPage.Elements.GetElement(String:anchorDyn).GetHtml() !!%>

nicht das gewünschte Ergebnis liefert. Denn beim Template Rendering wird der Elementname an der Content-Klasse und nicht der an der Instanz für die Abfrage herangezogen.

Nun gut, dann erweitern wir mal die Content-Klasse um diese Abfrage:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Management Server</title>
  </head>
  <body>
    <!IoRangeDynLink><%anchorDyn%><!/IoRangeDynLink>
    <!IoRangeDynLink><%containerDyn%><!/IoRangeDynLink>
    <hr/>
    <reddot:cms>
        <foreach itemname="objectPageElement" object="Context:CurrentPage.Elements">
            <output type="object" object="Store:Get(String:objectPageElement).Name" />
            <output type="object" object="Escape:Space" />
            <output type="object" object="Store:Get(String:objectPageElement).LinkName" />
            <output type="object" object="Escape:Br" />
        </foreach>
    </reddot:cms>
  </body>
</html>

Jetzt mal schauen was die Seitenvorschau uns ausgibt:

Sieht auf den ersten Blick gut aus und auf den zweiten seltsam. Denn die Sortierung der Elemente ist bei den dynamischen Anchor nicht exakt die selbe wie im Projektbaum. Warum ist das so? Um dieser Frage auf den Grund zu gehen, erweitern wir die Content-Klasse nochmals:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Management Server</title>
  </head>
  <body>
    <!IoRangeDynLink><%anchorDyn%><!/IoRangeDynLink>
    <!IoRangeDynLink><%containerDyn%><!/IoRangeDynLink>
    <hr/>
    <reddot:cms>
        <foreach itemname="objectPageElement" object="Context:CurrentPage.Elements">
            <output type="object" object="Store:Get(String:objectPageElement).Name" />
            <output type="object" object="Escape:Space" />
            <output type="object" object="Store:Get(String:objectPageElement).LinkName" />
            <output type="object" object="Escape:Space" />
            <output type="object" object="Store:Get(String:objectPageElement).Id" />
            <output type="object" object="Escape:Br" />
        </foreach>
    </reddot:cms>
  </body>
</html>

und schauen jetzt wieder in die Seitenvorschau:

Nun wird ersichtlich, warum die Sortierung der dynamischen Elemente nicht 1:1 mit der im Projektbaum übereinstimmt. Die Rückgabe erfolgt soriert nach der GUID (Id). Das sollte man sich merken und bei der Verwendung dieser Abfrage per Rendering-Template beachten.


Zwischenfazit: Man kann also doch auf dynamischen Elemente per Template Rendering zugreifen, in dem man sich alle Elemente der Seiteninstanz holt und dann per Schleife ausgibt.


Nun prüfen wir noch, ob wir an die Inhalte der verknüpften Seiten kommen. Dazu bauen wir nochmals diese Abfrage um:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Management Server</title>
  </head>
  <body>
    <!IoRangeDynLink><%anchorDyn%><!/IoRangeDynLink>
    <!IoRangeDynLink><%containerDyn%><!/IoRangeDynLink>
    <hr/>
    <reddot:cms>
        <foreach itemname="objectPageElement" object="Context:CurrentPage.Elements">
            <output type="object" object="Store:Get(String:objectPageElement).LinkName" />
            <output type="object" object="Escape:Space" />
            <output type="object" object="Store:Get(String:objectPageElement).GetLinkedContents()[Int32:0].Headline" />
            <output type="object" object="Escape:Br" />
        </foreach>
    </reddot:cms>
  </body>
</html>

und prüfen das Ergebnis mit der Seitenvorschau:

Das Ergebnis sieht erstmal korrekt aus und man kann darauf aufbauen. Folgendes sollte man noch beachten, wenn man weitere Elementtypen an der selben Content-Klasse hat. Denn dann ist es notwendig, dass man die Ergebnisse noch filtert:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Management Server</title>
  </head>
  <body>
    <!IoRangeDynLink><%anchorDyn%><!/IoRangeDynLink>
    <!IoRangeDynLink><%containerDyn%><!/IoRangeDynLink>
    <hr/>
    <reddot:cms>
        <foreach itemname="objectPageElement" object="Context:CurrentPage.Elements">
            <if>
                <query valuea="Store:Get(String:objectPageElement).Type.ToString()" operator="==" valueb="String:AnchorText">
                    <output type="object" object="Store:Get(String:objectPageElement).LinkName" />
                    <output type="object" object="Escape:Space" />
                    <output type="object" object="Store:Get(String:objectPageElement).GetLinkedContents()[Int32:0].Headline" />
                    <output type="object" object="Escape:Br" />
                </query>
                <query valuea="Store:Get(String:objectPageElement).Type.ToString()" operator="==" valueb="String:Container">
                    <output type="object" object="Store:Get(String:objectPageElement).LinkName" />
                    <output type="object" object="Escape:Space" />
                    <output type="object" object="Store:Get(String:objectPageElement).GetLinkedContents()[Int32:0].Headline" />
                    <output type="object" object="Escape:Br" />
                </query>
            </if>
        </foreach>
    </reddot:cms>
  </body>
</html>

und damit ist dann sichergestellt, dass man nicht andere Elementtypen mit den Methoden für Strukturelemente abfragt. Und damit dann im wsms.log ggfs. Fehlermeldung oder weitere Fehler im Template Rendering verursacht.

Viel Spaß beim ausprobieren ;)


Über den Autor:
Thomas Pollinger

... ist Senior Site Reliability Engineer bei der Vodafone GmbH in Düsseldorf. Seit dem Jahr 2007 betreut er zusammen mit seinen Kollegen die OpenText- (vormals RedDot-) Plattform Web Site Management für die deutsche Konzernzentrale.

Er entwickelt Erweiterungen in Form von Plug-Ins und PowerShell Skripten. Seit den Anfängen in 2001 (RedDot CMS 4.0) kennt er sich speziell mit der Arbeitweise und den Funktionen des Management Server aus.