Question about Fields

Topics: Customizing Orchard, General, Troubleshooting, Writing modules
Jan 11, 2012 at 2:24 AM

I defined a custom field, HtmlStringField (an HTML text field with a TinyMCE editor). I'm not sure how to attach it to my parts though. I have a part defined with 8 string fields. Right now my part's properties are just System.String, and when creating the db table for the part I defined the columns as strings.

I want my part's properties to be of type HtmlStringField, so that when I edit them in the dashboard, I get one tinyMCE editor for each property. 

I got how to define the custom field, and I think that's all done. I went in and modified my Content Type definition from the Dashboard to include an instance of my HtmlStringField field, and in the dashboard I see the WYSIWYG editor, but it doesn't save to anywhere in the db (at least I don't think so, and when I load the eidt window back up the other fields reload with the previous values but the WYSIWYG editor is blank). 

So the part I'm unclear about is how to hook it up so the custom field saves to a specific column of my ContentPartRecord's table. I would think at the very least I need to set up the mapping, but also how does Orchard know how cast/convert the field to the type of the db column? 

Jan 11, 2012 at 3:15 AM

I think I am one step closer. I have done this now: 

                , t =>
                        .WithField("HusbandBlurb", field => field.OfType(typeof(HtmlStringField).Name))
                        .WithField("WifeBlurb", field => field.OfType(typeof(HtmlStringField).Name))

But it doesn't look like it's saving to the db. I'm not sure what db table to look for to see if the values save, but the editor page in the Dashboard loads the wysiwyg fields blank.  

Jan 11, 2012 at 3:33 AM

Isn't there already a HtmlField?

Jan 11, 2012 at 12:49 PM

Yes there is one in the Gallery. I didn't find out about it until after I created my own. Even so, I would still like to know what i'm doing wrong, and also where custom fields save their data to. I am likely to want to create my own fields in the future. 


I imagined custom fields were like properties of a part, and they saved to a column in the part's db table just like normal properties but it appears this isn't the case? I don't see any db table whose name implies it handles saving fields, and I don't see any new db tables created after I defined my custom field. 

Jan 11, 2012 at 1:21 PM
Edited Jan 11, 2012 at 1:23 PM

In case anyone else is curious I found how Custom Fields are saved. 

As a test I made a new Content Type called "Kitchen", and added a Text Field called "Pot" (the only ContentField that comes with Orchard by default). Made a new Kitchen Content Item, and entered "Silver one" as the value for the "Pot" text field.

select * from [orch1x_Orchard_Framework_ContentItemVersionRecord]


A Gives this XML result: 

<Data><Kitchen><Pot>Silver one</Pot></Kitchen></Data>


My custom HtmlString field's value doesn't get saved to this table. I get an empty <Data> tag:

<Data />

Jan 11, 2012 at 5:54 PM

All the field properties are stored with an Infoset, same as TypePartSettings and so on. If you look at the HtmlField module you can see how it's done - some sort of field storage call you need to make, what does your driver look like?

Jan 11, 2012 at 6:19 PM


    public class HtmlStringFieldDriver : ContentFieldDriver<HtmlStringField>
        public IOrchardServices Services { get; set; }

        public Localizer T { get; set; }

        public HtmlStringFieldDriver(IOrchardServices services)
            Services = services;
            T = NullLocalizer.Instance;

        private static string GetPrefix(HtmlStringField field, ContentPart part)
            // handles spaces in field names
            return (part.PartDefinition.Name + "." + field.Name).Replace(" ", "_");

        private string GetDifferentiator(HtmlStringField field, ContentPart part)
            return field.Name;

        protected override DriverResult Display(ContentPart part, HtmlStringField field, string displayType, dynamic shapeHelper)
            return ContentShape(
                "Fields_Custom_HtmlString" // key in shape table
                , GetDifferentiator(field, part)
                , () => shapeHelper.Fields_Common_HtmlString(Name: field.Name, Html: field.Html)

        protected override DriverResult Editor(ContentPart part, HtmlStringField field, dynamic shapeHelper)
            var viewModel = new HtmlStringFieldViewModel { Html = field.Html, AddMediaPath = new PathBuilder(part).AddContentType().AddContainerSlug().AddSlug().ToString() }; 
            return ContentShape(
                , GetDifferentiator(field, part)
                , () => shapeHelper.EditorTemplate(
                    TemplateName: "Fields/Fields.Custom.HtmlString.Edit"
                    , Model: viewModel
                    , Prefix: GetPrefix(field, part)

        protected override DriverResult Editor(ContentPart part, HtmlStringField field, IUpdateModel updater, dynamic shapeHelper)
            updater.TryUpdateModel(field, GetPrefix(field, part), null, null);
            return Editor(part, field, shapeHelper);

        protected override void Importing(ContentPart part, HtmlStringField field, ImportContentContext context)
            var importedText = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "HtmlString");
            if (importedText != null)
                field.Html = importedText;

        protected override void Exporting(ContentPart part, HtmlStringField field, ExportContentContext context)
            context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("HtmlString", field.Html);

        protected override void Describe(DescribeMembersContext context)
            context.Member(null, typeof(string), T("Value"), T("The html code associated with the field."));
Jan 11, 2012 at 6:39 PM

Nothing obviously wrong there. (Though you could debug through to see what happens at updater.TryUpdateModel(..)  What does your HtmlStringField class look like?