A while ago I wrote a blog post, showing you how you can implement your own widget to associate any content item with an image. A lot of people had interest in such a task, at least judging by the comments all of you left. With this next installment, I’m going to extend the image selector and show you how to implement the two most requested features:
- Filtering the images by album
- Extracting the image selector in its own project/assembly.
To keep things short, I’ll assume you’ve read the other blog post. Before we move on with the implementation, take a look at the following screencast, showing you the end result: Image Selector for News with Album Filtering.
You can download the source code for this example from here.
For the sake of simplicity, let’s start with bullet number 2. Unlike the previous blog post, the whole image selector is extracted in its own assembly. The structure of the project is somewhat different from the one in the previous blog post. Because of this I recommend that you start from scratch, even if you have used the old project. Here are the steps you need to follow:
- Download the source code and open it.
- Extract the ThumbnailSelectorField folder from the archive to a location of your choice. I recommend that it is a sibling folder of the one containing your web application. My files after the extraction look like this:
- Open your web project in Visual Studio
- Add an existing project to the solution, and locate the ThumbnailSelectorField from the extracted folder. After this step, your visual studio solution should look like this:
- Extract the Global.asax files from the archive to the root folder of your web project. Include them in the Visual Studio project (if you don’t see them show all files from the toolbar button in Solution Explorer).
- Include a project reference to the ThumbnailSelectorField project in your web project.
- At this point your solution should build without errors. Save the solution file in the root web application folder if it prompts you to do it.
- Run the project, and create a custom field for a chosen module, as shown in the screencast. (Setup the database connection once prompted, if you haven’t done this already).
- The custom field should be of type Short Text.
- The custom type for the UI widget should be Telerik.Sitefinity.Samples.SimpleImageField.
- Upload some images and create some albums if there aren’t any.
- All done. You should be able to assign images to each content item.
Embedded templates and scripts
As you can see, the downloaded class library project contains all files for the image selector, including the scripts and templates. The scripts and templates are embedded resources, not regular files (you can see this in the BuildAction property of each file). Because of this, we need to do some plumbing.
- Register a prefix to load the widget templates (ASCX files) as embedded templates from the new assembly.
This is done by the code in Global.asax. More information for widget templates and how they are used by Sitefinity can be found here.
- Let ASP.NET know it has to load scripts from the assembly and send them to the client
If you have client code as an embedded resource, you can directly instruct ASP.NET to serve it to the browser. Same goes for CSS files. This is done by adding an entry for each file in the AssemblyInfo.cs file of the project. The source code you have downloaded already has the needed entries:
Our image selector uses its own CSS, and we need to change the code that loads it, to get it from the embedded resource, rather than an actual file (like it used to be in the previous version). This is done by the following code in SimpleImageSelector.cs:
Filtering by Album
If you have followed the above instructions correctly, then you should have a widget working from its own project. With this, one of the requested features is done. The other requirement involves writing a little more code. Implementing filtering by album can be broken down into the following steps:
- Include a control to display a list of albums in the template for SimpleImageSelector
- Bind the list of albums using a GenericCollectionBinder
- Handle the click to filter the list of images
The first step is simple. We only need a placeholder, where the binder will generate the markup for all albums. In our case this is a UL tag. Here’s the whole selector with the two placeholders – one for a list of albums, and one for a list of images (all DIV tags are there for easier styling and have no functional role):
The binding of the album list is very similar to the binding of the images list. We just need another instance of the GenericCollectionBinder. The only things we have to change are the service it binds to (Albums instead of images), and the markup for displaying a single item:
We now have everything we need in the template, time to write the code that does the actual binding. In the client component for the selector, there is a new property for the new album binder. We only need to call the DataBind() method.
As you can see, we also take note of what is the original URL for the image service. The reason is that when a single album is clicked by the user, the URL changes. Each next click changes the URL by appending the album ID to the original URL (to only retrieve images in that album). This is done, when handling the click command:
When an album is clicked, we get its ID, update the URL of the service to include this ID, and then rebind the list of images. That’s all there is to it.
One more small update in the selector is that instead of URLs, it now keeps the IDs of selected images. The benefit this gives us is that if the URL of an image changes, the selector will not break and will still show the correct image.
If you are not the type of person to implement all the above code, just download the project and follow the installation instructions. I’ve included the implementation as a showcase of working with binders and services. There are easier ways to achieve the same scenario by using our built-in selectors, but this is a topic for another blog post. Happy coding! Let us know what you think in the comments.