How to display an image gallery for each news item

How to display an image gallery for each news item

Posted on May 21, 2012 0 Comments

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.

An image gallery for a single news item

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.

A selector for a single image

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:

  • A selector control, which displays a list of images and returns the ID of the one clicked by the user
  • A dialog which wraps the selector control and returns the ID of the image when closed
  • A field control with two modes:
    • Write mode (used in the backend to select the image) – opens the dialog and saves the returned image ID.
    • Read mode (used to display the selected image in the news widget template) – reads the image ID, and outputs an <img> tag with correct URL.

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.

What needs to be changed

To support multiple images, we need to change the following from our previous sample:

  • Modify the selector to allow multiple selection
  • Modify the field control to display all images in Read Mode.

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.

Modify the selector to allow multiple selection

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.

Modify the field control to display all images in Read Mode

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.

Including the field control in a widget template

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.

Installation Instructions

  1. Create an empty Sitefinity project
  2. Download the source code for the sample
  3. Include the Global.asax and Global.asax.cs files in your web project
  4. Include the existing ThumbnailSelectorField project from the archive, and change its references to point to the BIN folder of your web project. Also include a project reference to it in the web project
  5. Build and run your project
  6. Create a custom field in News with name “Thumbnails” and select a Custom widget for entering data. Enter “Telerik.Sitefinity.Samples.SimpleImageSelector” for the widget type.
  7. Edit the widget template for the Full news item mode of news.
  8. Register the “samples” prefix with the following line:
    <%@ Register Assembly="ThumbnailSelectorField" Namespace="Telerik.Sitefinity.Samples" TagPrefix="samples" %>
  9. Include the field control in <ItemTemplate> section
    <samples:SimpleImageField ID="imgGalleryField" runat="server" Value='<%# Eval("Thumbnails") %>'></samples:SimpleImageField>

If you have further questions about the sample, please ask them in the comments.

progress-logo

The Progress Team

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.

Comments

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation