Click here to Skip to main content
Click here to Skip to main content

How to Build an Album Web Page with AJAX and ASP.NET MVC3

, 22 May 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Learn how to build an interface that allows you to scroll through thumbnails in an album and view each selected image.

Introduction

Viewing sets of images such as albums is a common functionality of many web applications. In this article we will take how to quickly build such functionality with Unobtrusive AJAX in an ASP.NET MVC 3 environment. Specifically, we want our application to have this functionality:

  • Scroll bar to view the thumbnail images in a set or album.
  • Main portion of the page that let's you see the selected image.
  • The selected thumbnail image needs to be highlighted.

Background

The tricky part in this task is that we need to be able to dynamically build clickable thumbnail images that make the appropriate action call to load the selected image.

Using the Code

There are many moving parts to get our album page working. We need to set up our model followed by the controller and the views. But first let's take care of the references and CSS classes. In your _Layout page make sure your are referencing the following jQuery files:

  • jquery-1.5.1.min.js
  • jquery.unobtrusive-ajax.min.js

In the web.config file you must also have an application setting allowing the use of unobtrusive AJAX:

<add key="UnobtrusiveJavaScriptEnabled" value="true"/>

In your CSS class we need to have a style to highlight the clicked image.

img.highlighted {
    border: 2px solid blue;
}

Models

First class we need to add to our models folder is the HTML helper for our action links. This code will be used later to create HTML img tags for the thumbnails.

public static class ImageActionLinkHelper
    {
        public static IHtmlString ImageActionLink(this AjaxHelper helper, string imageUrl, string altText, string titleText, string actionName, object routeValues, AjaxOptions ajaxOptions)
        {
            var builder = new TagBuilder("img");
            builder.MergeAttribute("src", imageUrl);
            builder.MergeAttribute("alt", altText);
            builder.MergeAttribute("title", titleText);
            var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions);
            return MvcHtmlString.Create(link.ToString().Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)));
        }

    }

Next up is our Image model which will contain the image objet itself along with the name of the image. Feel free to add any other fields you think should go along with the image. Most important methods here are to retreive the images. In the demo example I'm retrieving files from the local hard drive, but you can easily adapt this code to retieve from a DB. The other important function returns the thumbnail, minimizing the network traffic between server and client to boost performance.

public class YourImage
    {
        public string ImageID { get; set; }
        public byte[] ImageBytes { get; set; }
    
    public static byte[] GetImage(YourImage yourImage, bool isThumbnail)
        {
            byte[] image = yourImage.ImageBytes;

            // convert to thumbnail if necessary
            if (isThumbnail)
            {
                MemoryStream ms = new MemoryStream(image);
                Image returnImage = Image.FromStream(ms);
                // convert to thumbnail to improve loading time and reduce memory usage
                returnImage = returnImage.GetThumbnailImage(100, 100, ThumbnailCallback, IntPtr.Zero);

                MemoryStream output = new MemoryStream();
                returnImage.Save(output, ImageFormat.Jpeg);
                return output.ToArray();
            }

            return image;
        }

    public static List<YourImage> GetImageList(string folder)
        {
            List<YourImage> imList = new List<YourImage>();
            string[] fileEntries = Directory.GetFiles(folder);
            foreach (string picturePath in fileEntries)
            {
                YourImage urImage = new YourImage();
                string pictureName = picturePath.Substring(picturePath.LastIndexOf("\\") + 1, (picturePath.Length - picturePath.LastIndexOf("\\") - 1));
                urImage.ImageID = pictureName;
                Image currImage = Image.FromFile(picturePath);
                
                MemoryStream output = new MemoryStream();
                currImage.Save(output, ImageFormat.Jpeg);
                urImage.ImageBytes = output.ToArray();

                imList.Add(urImage);
            }
            return imList;
        }
    // Other code ommited for brevity
}

Controller

Next up is the code for the controller, which is fairly small, so that thumbnail list can be pulled as well as the selected image.

public class ImageController : Controller
    {
        //
        // GET: /Image/

        public ActionResult Index()
        {
            string folder = ConfigurationManager.AppSettings["ImagesFolder"];
            List<YourImage> imageList = YourImage.GetImageList(folder);
            Session["ImageList"] = imageList;
            YourImage currImage = imageList.FirstOrDefault();
            TempData["CurrentImage"] = currImage;
            return View(imageList);
        }

        public ActionResult GetYourImage(string imageName, bool isThumbnail)
        {
            // retrieve the object
            List<YourImage> shlist = (List<YourImage>)Session["ImageList"];
            YourImage shi = YourImage.GetYourImageFromList(imageName, shlist);
            byte[] image = YourImage.GetImage(shi, isThumbnail);

            if (image == null)
                return null;
            else
                return File(image, "image/jpg", imageName);
        }

        public ActionResult ImageDetails(string imageName)
        {
            List<YourImage> shlist = (List<YourImage>)Session["ImageList"];
            YourImage shi = YourImage.GetYourImageFromList(imageName, shlist);
            return PartialView(shi);
        }
    }

Views

First up is the Index view where most of the content is held, the list of the thumbnails as well as the selected image section. First up we need to place some jQuery to toggle between the selected thumbnails. You can add this to the top of the Index view.

$(function () {
    $('#select-form img').click(
    function () {
        // Set the form value
        $('#image-value').val($(this).attr('data-value'));

        // Unhighlight all the images
        $('#select-form img').removeClass('highlighted');
        // Highlight the newly selected image
        $(this).addClass('highlighted');
    });
});

The most critical piece is the thumbnail links that will be generated inside the for loop as you iterate over each thumbnail. Here the action links are nested as we need to generate a source URL for the image as well as the hyperlink to call the action to update the selected image. The AjaxOptions instruct where the action result will render, replacing the html within the currentFullImage <div> This is the part where our custom HTML extension comes into play. Make sure the name of the div matches the UpdateTargetId parameter.

@Ajax.ImageActionLink(@Url.Action("GetYourImage", "Image", new { imageName = item.ImageID, isThumbnail = true }),
                                            "no image",
                                            "NoImageTitle",
                                            "ImageDetails",
                                            new { imageName = item.ImageID },
                                            new AjaxOptions { UpdateTargetId = "currentFullImage", InsertionMode = InsertionMode.Replace })

The next view is the ImageDetails view where the selected image is displayed.

@model ImageAlbumDemo.Models.YourImage
<br/>
<div id="currentFullImage">   
        <img src="@Url.Action("GetYourImage", "Image", new { imageName = Model.ImageID, isThumbnail = false })" 
                        alt="No Image" width="100%" height="100%" id="imgMain" /> 
</div>

Now we are ready to roll, here is the end result!

Points of Interest

Now that the app running, take a closer look at the HTML that has been generated by the ImageActionLink function. The thumbnail image object is located inside the hyperlink element <a>.

<a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#currentFullImage" href="http://www.codeproject.com/Image/ImageDetails?imageName=clip-art-circus-465619.jpg">
<img alt="no image" src="http://www.codeproject.com/Image/GetYourImage?imageName=clip-art-circus-465619.jpg&isThumbnail=True" title="NoImageTitle" />
</a>

History

No updates as of yet.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Alex Taimassov
Web Developer
United States United States
I have been professionally working with .NET applications since 2006.
Follow on   LinkedIn

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411023.1 | Last Updated 22 May 2014
Article Copyright 2014 by Alex Taimassov
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid