Projection Query Sort By Part Property (not a field)

Topics: Customizing Orchard, General, Writing modules
Aug 20, 2012 at 9:44 PM
Edited Aug 20, 2012 at 9:49 PM

I've managed to create a CustomContentType via Migrations.cs with a CustomContentPart attached (and custom table (e.g. - "CustomContentPartRecord") to house the data for the part). This seems fairly standard according to all of the module creation tutorials I've seen. There are drivers and handlers and classes to manage all of this. Seems to work.

However, I created a query to pull all CustomContentType items, and I need to sort by one of the columns on my CustomContentPartRecord table (none of which are fields). 

How can I do this?

Aug 21, 2012 at 6:36 AM

 

using System;
using Orchard.Localization;
using Orchard.Projections.Descriptors.SortCriterion;
using Orchard.Projections.Services;

namespace YourModule {
    public class SortCriterionProvider : ISortCriterionProvider
    {
        public SortCriterionProvider() {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void Describe(DescribeSortCriterionContext describe) {
            var descriptor = describe.For("Custom Content Part", T("Custom Content Part"), T("Description..."));            
            descriptor.Element("PropertyName", T("Property Name"), T("Description of property"),
                context => ApplyFilter(context),
                context => DisplaySortCriterion(context)
            );           
        }

        public void ApplyFilter(SortCriterionContext context)
        {

            bool ascending = Convert.ToBoolean(context.State.Sort);
            context.Query = ascending
                ? context.Query.OrderBy(alias => alias.ContentPartRecord(typeof(YourPartRecord)), x => x.Asc("PropertyName"))
                : context.Query.OrderBy(alias => alias.ContentPartRecord(typeof(YourPartRecord)), x => x.Desc("PropertyName"));
        }

        public LocalizedString DisplaySortCriterion(SortCriterionContext context)
        {
            bool ascending = Convert.ToBoolean(context.State.Sort);

            if (ascending)
            {
                return T("Ordered by {0}, ascending", "PropertyName");
            }

            return T("Ordered by {0}, descending", "PropertyName");
        }
    }
}
Aug 22, 2012 at 3:56 PM

Thanks Brandon,

That worked perfectly! Added a sort criterion, restarted the app, and a new sort option appeared in the Sort listing for queries. When stepping through, context.State.Sort didn't exist on the context State, so it's always false (therefore making my sort always be descending). I can change this via code, but I was hoping to use the "Edit" link for my newly chosen sort to do that.

One hiccup, though, the "Edit" link that is generated next to my newly chosen sort item doesn't appear to work. Normally this would take me to a screen where I can rename my sort and choose ascending or descending. Instead, I click the link, and the current query screen just refreshes. 

Ideas? Or is that just the expected behavior?

Thanks, again!

Aug 22, 2012 at 4:38 PM
Edited Aug 22, 2012 at 4:45 PM

I found the answer to my problem. I needed to add the SortCriterionFormProvider.FormName property as shown below:

using System;
using Orchard.Localization;
using Orchard.Projections.Descriptors.SortCriterion;
using Orchard.Projections.Services;

namespace YourModule {
    public class SortCriterionProvider : ISortCriterionProvider
    {
        public SortCriterionProvider() {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void Describe(DescribeSortCriterionContext describe) {
            var descriptor = describe.For("Custom Content Part", T("Custom Content Part"), T("Description..."));            
            descriptor.Element("PropertyName", T("Property Name"), T("Description of property"),
                context => ApplyFilter(context),
                context => DisplaySortCriterion(context),
		SortCriterionFormProvider.FormName
            );           
        }

        public void ApplyFilter(SortCriterionContext context)
        {

            bool ascending = Convert.ToBoolean(context.State.Sort);
            context.Query = ascending
                ? context.Query.OrderBy(alias => alias.ContentPartRecord(typeof(YourPartRecord)), x => x.Asc("PropertyName"))
                : context.Query.OrderBy(alias => alias.ContentPartRecord(typeof(YourPartRecord)), x => x.Desc("PropertyName"));
        }

        public LocalizedString DisplaySortCriterion(SortCriterionContext context)
        {
            bool ascending = Convert.ToBoolean(context.State.Sort);

            if (ascending)
            {
                return T("Ordered by {0}, ascending", "PropertyName");
            }

            return T("Ordered by {0}, descending", "PropertyName");
        }
    }
}

Note: I needed to add a project reference to Orchard.Forms in order for the solution to build.
Thanks again, Brandon!

Aug 22, 2012 at 10:21 PM

Sounds good.   Sorry I forgot that form part.