Accessing currently displayed content parts in Orchard

Tags: orchard, module, parts, english

Sometimes you may need to acquire some knowledge about other parts displayed in the current request. The purposes can be different, from simple logging to displaying a content part which relies on other current content (eg. you want to differentiate the display basing on other existing content).

I needed it to record some information (path and title) about current RoutePart to create the BreadcrumbsWidget (which will arrive soon with the new release of Hierarchical Menu module). Although there are many ways to do that, this one is particularly useful when you don’t want to (or cannot) directly interfere with the other Content Parts. Bertrand Le Roy (as always helpful) gave me an idea to do that by pushing the information from content items instead of pulling. This can be useful in some cases, but unfortunately I wanted something simpler, so sticked to something less intrusive – leveraging the Content Handler’s events.

First of all, you have to create a interface of a service, which will track the parts you need and hold them throughout the single request.

public interface IPartWatcher : IDependency {
    void Watch<T>(T part) where T: IContent;
    IEnumerable<T> Get<T>() where T: IContent;
}

and the appropriate, simple implementation

public class PartWatcher : IPartWatcher {
    readonly HashSet<IContent> _parts = new HashSet<IContent>();

    public void Watch<T>(T part) where T : IContent {
        _parts.Add(part);
    }

    public IEnumerable<T> Get<T>() where T : IContent {
        return _parts.Where(p => p.Is<T>()).Select(p => p.As<T>());
    }

}

 

Now, that we have our service that will hold the parts we want, we have to fill it with necessary data. This can be done by a simple implementation of ContentHandler (the same you write for your content parts – this time we won’t connect it with any content part).

[UsedImplicitly]
public class PartWatcherHandler : ContentHandler {
    public PartWatcherHandler(IPartWatcher service)
    {
        OnGetDisplayShape<RoutePart>((ctx, part) => service.Watch(part));
    }
}

 

This part of code registers a lambda expression to the handler’s event, OnGetDisplayShape, which is fired when Orchard displays an item containing the RoutePart. This ensures that parts that will be watched by PartWatcher are currently being displayed. Lambda is very simple and only tells the PartWatcher to watch this particular part.

Cool! This is exactly what I needed, in a clean and simple way UĊ›miech

You can, of course, use other events (eg. OnIndexing) and track different content parts, depending on what you want to achieve.

Now, the last thing left is to inject the IPartWatcher service to your driver/handler/etc. constructor and use it!

Cheers!

blog comments powered by Disqus