Olof Törnqvist

Teknik

Teknik

Flexible page content modeling

Flexible page content modeling (using CMS:ForEach)

You can do a lot with the regular HTML-editor in Camelonta CMS but sometimes you want to make it easier for the editor to add nice looking formatted pieces of data to the site without the hassle of formatting it themselves or you want to force a specific design on the site. For example an image with an author name attached to the bottom of it or a movie with a header and a summary. That is easily done with the Panel element like this.

<Element Name="ImageWithAuthor" Type="Panel">
 <Label xml:lang="en">Image with an author</Label>
 <Element Name="Image" Type="ImageChooser">
   <Label xml:lang="en">Image</Label>
 </Element>
 <Element Name="Author" Type="TextField">
   <Label xml:lang="en">Author</Label>
 </Element>
</Element>

 

Now you can retrieve the data in your template like this:

<CMS:Image PropertyFilename="ImageWithAuthor/Image" runat="server" />
<p>
   <CMS:Property PropertyName="ImageWithAuthor/Author" runat="server" />
</p>

 

Adding multiple elements

That is pretty simple but what if you want the editor to be able to add several of these images? Well, that is when we can use our handy ForEach-control. CMS:ForEach is a control that makes it possible to iterate over several elements. First we need to be able to add several of the ImageWithAuthor-panel. To do this we add the MaxOccurs-property that tells the PageType how many of this element can be added to the page. It can be a number or unbounded for an unlimited amount.

 

<Element Name="ImageWithAuthor" Type="Panel" MaxOccurs="unbounded">
 <Label xml:lang="en">Image with an author</Label>
 <Element Name="Image" Type="ImageChooser">
   <Label xml:lang="en">Image</Label>
 </Element>
 <Element Name="Author" Type="TextField">
   <Label xml:lang="en">Author</Label>
 </Element>
</Element>

 

If you edit your page now you will be able to add several of the ImageWithAuthor-element.

Ok, but if you add a couple of these elements and then preview the page you will only see the first one. Let’s fix this by adding our ForEach-control to iterate through them and render all of them instead.

 

<CMS:Foreach Property="ImageWithAuthor" runat="server">
   <ItemTemplate>
       <CMS:Image PropertyFilename="Image" runat="server" />
       <p>
           <CMS:Property PropertyName="Author" runat="server" />
       </p>
   </ItemTemplate>
</CMS:Foreach>

 

Now you should have a list with all of them. Try reordering the elements on the Edit Page and you’ll notice that the ForEach-control respects the order that you place them in. What is happening here? Well first we have added the ForEach-control around our previous template-code. It takes the name of the property we want to iterate over as a property. You can also see that we have removed the prefix ImageWithAuthor on the CMS:Image and CMS:Property tags. That is because inside the CMS:Foreach we are now in the context of the element ImageWithAuthor.

Iterating over several different elements at the same time

Ok let’s mix it up a little. We want to be able to add a header text in-between any of these images, so that we can group them together. We also want the editor to freely be able to decide the order of the images and headers.

First we add a new element in the Schema file:

<Element Name="Header" Type="TextField">
 <Label xml:lang="en">Header</Label>
</Element>

 

Then we change our ForEach like this:

<CMS:Foreach Property="Header|ImageWithAuthor" runat="server">
   <ItemTemplate>
       <CMS:If CurrentElementName="Header" runat="server">
           <h2><CMS:Property PropertyName="this" runat="server" /></h2>
       </CMS:If>
       <CMS:If CurrentElementName="ImageWithAuthor" runat="server">
           <CMS:Image PropertyFilename="Image" runat="server" />
           <p>
               <CMS:Property PropertyName="Author" runat="server" />
           </p>
       </CMS:If>
   </ItemTemplate>
</CMS:Foreach>

 

Let me walk you through the changes here. First we changed the property of the ForEach to Header|ImageWithAuthor. The pipe-sign is a union operator and this tells the control that we want to iterate through both of those elements at the same time. In the ForEach template we need to know what the current element is in order to apply different rendering depending on the element. To do that we use the If control and the CurrentElementName attribute.  If CurrentElementName is “ImageWithAuthor” then we print the same code as before. If it is “Header” we need to use the “this” keyword to reference the “Header”-element. Why use “this”? Well, remember before when I said that inside the ForEach-control we are in the context of the child element?  When we are in the Header-context we don’t have a child element to print as we do with ImageWithAuthor. Instead we just use the “this” keyword to print the current property instead.

Check out this page on out demo site to view a live example of how it may look

http://camelonta.se//img/default-facebook-share.jpg