Display custom field in module

Topics: Customizing Orchard
Dec 5, 2011 at 1:34 PM

Hi everyone,

This weekend I started creating my first Orchard project ever.  Luckily, I have been able to find some very good examples on the web.  However, I am running into a problem with a module I am trying to create, and I haven't been able to find the solution so far.

One of my customers would like to have a very simple event calendar.  I could probably use the standard list combined with a custom EventPart, which should of course be containable.  It should have some standard Orchard Content Parts, as well as "When" (DateTime) and "Archive" (DateTime) fields.  I was hoping to use the custom DateTimeField I downloaded from CodePlex.

I thought it would be possible to compose the part using the following data migration:

public class Migrations : DataMigrationImpl
    {
        public int Create()
        {
            ContentDefinitionManager.AlterTypeDefinition("EventPart",
                cfg => cfg
                    .WithPart("CommonPart")
                    .WithPart("RoutePart")
                    .WithPart("BodyPart")
                    .WithPart("ContainablePart")
                    .Creatable()
                );

            ContentDefinitionManager.AlterPartDefinition("EventPart",
                cfg => cfg
                    .WithField("When",
                        field => field
                            .OfType(typeof(DateTimeField).Name)
                        )
                );

            ContentDefinitionManager.AlterPartDefinition("EventPart",
                cfg => cfg
                    .WithField("Archive",
                        field => field
                            .OfType(typeof(DateTimeField).Name)
                        )
                );

            return 1;
        }
    }

After enabling the module, I can create a list, and add Event Parts to the list.  However, the form for creating an Event Part does not include the two custom fields, only the other parts I included.

Since I am new to Orchard, I am pretty sure I am missing something that would be very obvious to more experienced Orchard developers.  So I am hoping that someone can easily spot where I went wrong, and get me on the right track again.  Should I have defined views (cshtml files), for instance?  If so, how can I include the two custom fields?  Currently, the only files I have added to my project is the Migrations.cs with the code above, and I updated the generated Module.txt file in order to indicate the project depends on Contrib.DateTimeField (which, of course, I have also added as a reference).

I also have a question regarding the list and its sort order.  I would like the list to be sorted by the When field from the Event part.  Would that be possible?  I noticed there were a couple of predefined field, as well as approximately three custom fields, to choose from in the sort order dropdown.  However, I don't know how to refer to the When field of my custom parts.

Some help and advice would be greatly appreciated!

Dec 5, 2011 at 2:02 PM

Duh...  Why does this always happen five minutes after you post something?

After posting, I noticed that I was calling two different types of methods, one for types, and one for parts.  I had copied and pasted bits of code I had found elsewhere.  So, after adjusting the Create method, it now looks like this:

 

public int Create()
        {
            ContentDefinitionManager.AlterPartDefinition("EventPart",
                cfg => cfg
                    .WithField("When",
                        field => field
                            .OfType(typeof(DateTimeField).Name)
                        )
                );

            ContentDefinitionManager.AlterPartDefinition("EventPart",
                cfg => cfg
                    .WithField("Archive",
                        field => field
                            .OfType(typeof(DateTimeField).Name)
                        )
                );

            ContentDefinitionManager.AlterTypeDefinition("Event",
                cfg => cfg
                    .WithPart("CommonPart")
                    .WithPart("RoutePart")
                    .WithPart("BodyPart")
                    .WithPart("EventPart")
                    .WithPart("ContainablePart")
                    .Creatable()
                );

            return 1;
        }

That takes care of displaying the "When" and "Archive" fields.  Now, I have two remaining questions:

1.  How would I sort a list by the "When" field of my event?

2.  Would it also be possible to filter the list, to include only those elements that either have no archive date, or an archive date that is in the future?

I am currently using the built-in list functionality to list my events, but have already been able to create a custom list, by using code as shown here:

ContentDefinitionManager.AlterTypeDefinition("EventtList",
    cfg => cfg
            .WithPart("BodyPart")
                   .WithPart("CommonPart")
                .WithPart("RoutePart")
                .WithPart("MenuPart")
                .WithPart("ContainerPart")
                .Creatable());

However, I don't know how I might be able to sort or filter it.

Dec 5, 2011 at 4:56 PM

The Lists module is very basic and doesn't provide any sort/filter functionality. You can either build a custom module to extend the content item yourself, or wait for Projector which is a new Orchard feature in development: http://orchard.codeplex.com/discussions/274915

Also, my Mechanics module lets you build more complex relationships between content, and you can hook in your own sorters and filters, although sorting on a field isn't actually possible at the moment with ContentQuery and you'd have to build your own ContentPart instead to be able to sort on that value.

Dec 5, 2011 at 7:30 PM

Thanks for the quick reply.  The Projector sounds like it could be the perfect solution to my problem.  However, my project needs to be finished before Christmas.  Do you know when the Projector feature will be available?

If I can't use the Projector feature and need to build my own custom module to do this, can you give me a few quick pointers that will help be get started?  As I mentioned in my other message, I am very new to Orchard.  I am impressed by the many ways in which it can be extended, however, that also makes it more difficult to jump right in when you have to do something very specific. :-)

Or maybe there is another, possibly easier, way in which I can create the functionality my customer is looking for?  Considering my limited knowledge, I may have chosen the wrong type of solution.  The main requirements are that

- it should be possible to create Event items, with "When" and "Archive" date/times that preferably use the editor that comes with the DateTimeField.

- it should be possible to list the Event items, sorted by the "When" date, and filtered by an "Archive" date that must be either empty or in the future.

Dec 5, 2011 at 7:55 PM
Edited Dec 5, 2011 at 7:55 PM

I gave you a link above to the Projector development thread, there is information there about the current status of Projector - it is available on the 1.x branch but not all features are 100% working as I understand it.

But, you could still think about using Mechanics to achieve this in the very near future. I'm doing some work on the module as we speak which will make it pretty easy to display lists like this.

Just to give the run down: the main feature of Mechanics is content connections, but it also has a feature called Plumbing, which gives you some content parts that you can using instead of RoutePart (the one built into Orchard). One of the things this new routing part gives you is an option to specify a BasePath (or autogenerate one from the content type). So this would give you routes like: /events/our-launch-event. The plan has always been to have /events then be a list of all content of that type; with paging of course, and the ability to plug in custom sorters and filters. This plan hasn't been fully realised yet, although all the support is in there for that scenario, and I've just been making a huge amount of changes to the codebase which should include the above becoming possible. All you'd have to do is build a custom ContentPart with When and Archive records, then you can plug in your custom filtering and sorting (and there's already a simple extensibility point to do that).

I can't accurately promise anything, but I guess by the end of the week I should have things working, of course if you need it sooner you could always help out ;)

Actually, having said all that, I realised you could just go the incredibly straightforward solution of writing a controller. In your index action you can use IContentManager to query, sort and filter the items, then render them into a list in Summary view (or any display mode you want of course) and return that in a ShapeResult.

Dec 5, 2011 at 8:22 PM

Thanks again.  I did read through the messages in the Projector development thread, just couldn't figure out when it would be available.  It sounds like a great new feature.

I think I will see if I can implement the controller solution for now.  I do have ASP.Net MVC experience so, for now, that would probably be more familiar territory.  I just have to see if I can find an example that shows me how to use the IContentManager to query, sort and filter parts based on fields.

I will take a look at your Mechanics module as well, because it sounds like it can do interesting things.  I really wouldn't mind helping you out if I thought I would be able to.  But I'm afraid it would take more time for you to explain how things work (or are supposed to work) to me, than it would be for you to implement it on your own.  However, I will definitely take a look at it.  Even if it's too complicated for me to help you create it, I might be able to see if I could just test it with my Events stuff and maybe give you some input, but that really depends on how long it would take me to figure it all out.  I feel a bit like I am trying to run without having learned how to walk first. :-)