The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.
We’ve seen many requests for the option to associate a Sitefinity news item with a collection of images. A long time ago I blogged on how you could associate a single news item with a single image. Extending that sample to enable multiple image selection is not very hard, and this blog post is going to show you how to do it.
If you just want the source code for the sample, you can download it. Follow the installation instructions at the end of the blog post.
The sample you can read about in the previous blog post implements a single image selector. This is a summary of what has been implemented so far:
NOTE: This blog post is an extension to the previous one. It will only go over the new functionality and changes, so if you haven’t gone through the initial implementation, I recommend you do that now.
To support multiple images, we need to change the following from our previous sample:
We will go over each of the above items and see how it was implemented. The way the dialog returns the selected images, and how the field control persists them in the custom field stays the same. Instead of saving the ID, we will save a comma-separated list of IDs.
The image selector should be able to highlight multiple selected images. In the previous sample, any time you click an image, your previous selection was lost (because you could only select one). This is all done in the Javascript _binderCommand method of the SimpleImageSelector. Here is the changed code that handles multiple image selection:
if
(args.get_commandName() ==
"selectImage"
) {
var
imageUrl = args.get_dataItem().ThumbnailUrl;
var
imageId = args.get_dataItem().Id;
var
jItemElement = jQuery(args.get_itemElement())
var
isItemAlreadySelected = jItemElement.attr(
'class'
).indexOf(
'sf_selectedImage'
) != -1;
if
(isItemAlreadySelected) {
var
itemIndex =
this
.arrayContains(
this
._selectedImageIds, imageId);
if
(itemIndex !== -1) {
this
._selectedImageIds.splice(itemIndex, 1);
}
var
itemIndexUrl =
this
.arrayContains(
this
._selectedImageUrls, imageUrl);
if
(itemIndex !== -1) {
this
._selectedImageUrls.splice(itemIndex, 1);
}
jItemElement.removeClass(
"sf_selectedImage"
);
}
else
{
if
(
this
.arrayContains(
this
._selectedImageIds, imageId) === -1) {
this
._selectedImageIds.push(imageId);
}
if
(
this
.arrayContains(
this
._selectedImageUrls, imageUrl) === -1) {
this
._selectedImageUrls.push(imageUrl);
}
jItemElement.addClass(
"sf_selectedImage"
);
}
}
The ID of the image that was clicked is passed as an argument. We keep the IDs and URLs of the already selected images in two arrays. These arrays were not present in the previous sample, where we only kept a single ID and URL. We check if the item is already added, and add or remove it accordingly. Each new item the user clicks will be added to the array, or removed on second click. The code for changing the style of the selected image and returning the selected value does not change.
Once a collection of images is selected, the value is persisted as a comma-separated string of their IDs. We need to parse that string and get the images themselves using the API. In the previous version, with only one image to select, the Value property of the field control was returning the ID directly from the UI. We now need to add a private field to hold the value. Here is the full implementation of the Value property.
public
override
object
Value
{
get
{
var val =
string
.Empty;
switch
(
this
.DisplayMode)
{
case
FieldDisplayMode.Read:
if
(
this
.value !=
null
)
val =
this
.value.ToString();
break
;
case
FieldDisplayMode.Write:
if
(
this
.value !=
null
)
val =
this
.value.ToString();
break
;
}
return
val;
}
set
{
if
(
this
.ChildControlsCreated)
{
switch
(
this
.DisplayMode)
{
case
FieldDisplayMode.Write:
this
.TextBoxControl.Text = value
as
string
;
break
;
case
FieldDisplayMode.Read:
var imageIds = value.ToString().Split(
';'
);
this
.value = imageIds;
break
;
}
this
.value =
null
;
}
else
{
this
.value = value;
}
}
}
Apart from doing the selection itself, our field control also has the job of presenting the selected images when used in Read mode (i.e. the widget template of a widget). For the purposes of this sample, we will just bind a Repeater control to the list of images. This is done in three of the methods – OnLoad, InitializeControls, and OnPreRender.
protected
override
void
OnLoad(EventArgs e)
{
base
.OnLoad(e);
if
(
this
.DisplayMode == FieldDisplayMode.Read)
this
.ImageGalleryControl.ItemDataBound +=
new
RepeaterItemEventHandler(ImageGalleryControl_ItemDataBound);
}
protected
override
void
InitializeControls(GenericContainer container)
{
this
.ConstructControl();
if
(
this
.DisplayMode == FieldDisplayMode.Read)
{
this
.LabelControl.Visible =
false
;
}
}
protected
override
void
OnPreRender(EventArgs e)
{
base
.OnPreRender(e);
if
(
this
.DisplayMode == FieldDisplayMode.Read)
{
var filterBuilder =
new
StringBuilder();
var imageIds =
this
.Value.ToString().Split(
','
);
for
(var i = 0; i < imageIds.Length; i++)
{
if
(i > 0)
{
filterBuilder.Append(
" OR "
);
}
filterBuilder.Append(String.Format(
"Id == {0}"
, imageIds[i]));
}
var filter = filterBuilder.ToString();
var images = App.WorkWith().Images().Where(i => i.Status == ContentLifecycleStatus.Master).Where(filter).Get();
this
.ImageGalleryControl.DataSource = images;
this
.ImageGalleryControl.DataBind();
}
}
void
ImageGalleryControl_ItemDataBound(
object
sender, RepeaterItemEventArgs e)
{
if
(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var imageControl = e.Item.FindControl(
"image"
)
as
System.Web.UI.WebControls.Image;
if
(imageControl !=
null
)
{
imageControl.ImageUrl = (e.Item.DataItem
as
Telerik.Sitefinity.Libraries.Model.Image).ThumbnailUrl;
}
}
}
By using the Split() method, we convert the comma-separated string of IDs into an array. From those IDs, we build a filter, which can be passed to the API to get a collection of the selected images. The we just set the Repeater’s data source and call its DataBind() method. On the ItemDataBound event of the Repeater, we set the URL of each <img> tag to the selected image’s thumbnail.
Once we’ve implemented multiple selection in our field control, we can include it in the widget template for each news item. This is done with the following markup:
<%@ Register Assembly="ThumbnailSelectorField" Namespace="Telerik.Sitefinity.Samples" TagPrefix="samples" %>
...
<
samples:SimpleImageField
ID
=
"imgGalleryField"
runat
=
"server"
Value='<%# Eval("Thumbnails") %>'></
samples:SimpleImageField
>
Note that in the Value property, we need to supply the name of the custom field which we use to persist the selected images. The next section lists all steps you need to follow in order to setup the multiple image selector for the News module.
If you have further questions about the sample, please ask them in the comments.
View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites
Progress collects the Personal Information set out in our Privacy Policy and the Supplemental Privacy notice for residents of California and other US States and uses it for the purposes stated in that policy.
You can also ask us not to share your Personal Information to third parties here: Do Not Sell or Share My Info
We see that you have already chosen to receive marketing materials from us. If you wish to change this at any time you may do so by clicking here.
Thank you for your continued interest in Progress. Based on either your previous activity on our websites or our ongoing relationship, we will keep you updated on our products, solutions, services, company news and events. If you decide that you want to be removed from our mailing lists at any time, you can change your contact preferences by clicking here.