List properties
Describes how to model lists of multiple values.
Most property types in Optimizely Content Management System (CMS) can be modeled as lists, including types modeled as block types. For example, given that there is a block type modeled as:
[ContentType(AvailableInEditMode = false, GUID = "38d57768-e09e-4da9-90df-54c73c61b270")]
public class ContactBlock : BlockData {
//block properties
}
Then, other Content models can define lists of the block type as:
public virtual IList<ContactBlock> Contacts {
get;
set;
}
Each list item looks the same when collapsed – you see just the type name. However, you can override that and specify which property should be used when rendering list item header.
[ListItemHeaderProperty(nameof(Blocks.ContactBlock.Heading))]
public virtual IList<ContactBlock> Contacts {
get;
set;
}
The idea is the same as with the List<T>
you add the list as a property to your model, and the default descriptors match IList
 type and render the correct editor. For example:
public virtual IList<string> ListOfStrings {
get;
set;
}
public virtual IList<int> ListOfIntegers {
get;
set;
}
public virtual IList<DateTime> ListOfDates {
get;
set;
}
public virtual IList<XHtmlString> ListOfXhtml {
get;
set;
}
You can also define a list property with a custom type inside, which you should not use as a block in the system. You only need an editor and descriptor for a single property, and it is used if the property is used within a list. For example, if there is a custom editor for a type GeoCoordinate
which is defined like this:
public virtual IList<GeoCoordinate> Contacts {
get;
set;
}
...where GeoCoordinate
is...
public class GeoCoordinate {
public decimal Latitude {
get;
set;
}
public decimal Longtitude {
get;
set;
}
public int Zoom {
get;
set;
}
}
...and then there is a custom type descriptor for GeoCoordinate
which defines a custom editor...
[EditorDescriptorRegistration(TargetType = typeof (GeoCoordinate))]
public class GeoCoordinateEditorDescriptor: EditorDescriptor {
public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes) {
ClientEditingClass = "alloy/editors/GoogleMapsPicker";
base.ModifyMetadata(metadata, attributes);
}
}
...GeoCoordinate
must be inherited from BlockData
or a custom BackingType
has to be provided.
[ContentType(AvailableInEditMode = false, GUID = "11d57768-e09e-4da9-90df-54c73c61b270")]
public class GeoCoordinate: BlockData {
public virtual decimal Latitude {
get;
set;
}
public virtual decimal Longtitude {
get;
set;
}
public virtual int Zoom {
get;
set;
}
}
Note
The
AvailableInEditMode
attribute andvirtual
modifier are added to all model properties.
You can provide a custom UIHint
to the list item. For example, you can create a list of images or video files:
[UIHint(UIHint.Image)]
public virtual IEnumerable<ContentReference> Images {
get;
set;
}
...which is rendered like this:
Note
The property type does not have to be
IList
. The Optimizely descriptors are configured to match the IList interface but they also cover all base ones, so if you prefer to useIEnumerable
orICollection
you can do so. All the following declarations are matched by the Value List descriptor.
public virtual IEnumerable<string> EnumerableStrings {
get;
set;
}
public virtual ICollection<string> CollectionOfStrings {
get;
set;
}
public virtual IList<string> ListOfStrings {
get;
set;
}
Validate a list
You can apply validation to the list itself and the individual items, and you can use ListItemsAttribute
to control the number of items in the list:
[ListItems(5)]
public virtual IList<int> Max5Items {
get;
set;
}
You can apply the following attributes to individual items:
[ItemRangeAttribute(1, 10)]
public virtual IList<int> ItemsBetween1And10 {
get;
set;
}
[ItemRegularExpression("[a-zA-Z]*")]
public virtual IList<string> LettersOnly {
get;
set;
}
[ItemStringLength(3)]
public virtual IList<string> ListOfAcronyms {
get;
set;
}
You can also provide custom metadata and validators to the items inside the list. For example, if there is a List<ContactBlock>
defined, you can create a metadata extender just for ContactBlock
or have a custom validator of ContactBlock
and it is applied to each instance created within the list property.
Render a list
To render a list:
public virtual IList<string> UniqueSellingPoints {
get;
set;
}
To use the PropertyFor
helper method, you must define a specific Display template, and to do that, you must first attach a UIHint
to your property:
[UIHint("StringsCollection")]
public virtual IList<string> UniqueSellingPoints {
get;
set;
}
Then add a StringsCollection.cshtml
file to the ~/Views/Shared/DisplayTemplates
folder.
You can see an example of a Display Template in the Alloy package:
@model IEnumerable<string>
@if(Model != null && Model.Any())
{
<ul>
@foreach(var stringValue in Model) {
<li>@stringValue</li>
}
</ul>
}
Add a UniqueSellingPoints
property to your page template:
@Html.PropertyFor(x => x.CurrentPage.UniqueSellingPoints)
You will see the following result in the on-page edit:
The same with more complex types:
public virtual IList<ContactBlock> ContactBlocks {
get;
set;
}
The system looks for a partial view for ContactBlock
inside ~/Views/Shared/DisplayTemplates
and it will render the items as ul -> li by default.
However, you can create a custom display template for the whole list if a simple ul or list is insufficient.
Updated 6 months ago