The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.
Recently we've received some extremely valuable feedback regarding the need to explain in details how one can customize Sitefinity's UserProfile widget template to facilitate user input when the widget is in Edit mode. This post is going to attempt at doing it, showing you how you can utilize Sitefinity's FieldControls in Write mode to achieve your use case scenario.
First I'd like to add some context in the whole story by writing a few words about the UserProfile widget in general. By default this is one of our quite complex widgets - it offers the ability to display profile data from different UserProfile types, and at the same time facilitates editing and persisting this data. In addition this widget offers you the options to choose between "auto-generated" templates or using/customizing the predefined one. Last but not least you have the freedom to create entirely new templates.
The "auto-generated" templates option is most convenient for the users who want to let Sitefinity display all available properties for both Read and Edit modes of the widget. The way it works is very elegant - we take the UserProfile type you've selected, and read all properties that have been defined for this type through the profile configuration. Then for each property we read its Definition and show the corresponding FieldControl to facilitate the displaying and editing of its value.
There are use cases, though, where you want to specify explicitly which properties should be displayed, and offered for editing by the user. In these cases you should go with the custom template option. In this mode you're in full control, however there are some specifics which you should be aware of, and knowing them will make this task pretty straightforward to you.
By now you're probably asking yourself the question "why should there be any specifics"? As the saying goes - with great power comes great responsibilities. Although the answer is not that philosophical in our case, it's a good comparison. Remember when we said in the previous paragraph how Sitefinity knows about all properties it should display and what FieldControl to insert to facilitate working with a particular property when in "auto-generated" mode? Well, when you chose to go with custom template there's no way for it to know about this anymore - you're the one who's telling it which properties to show and which FieldControls should be used. But don't worry - there's nothing scary about it, let me show you :)
There are always more use case scenarios that what can be documented in writing. To avoid simply telling you - for property of type X always use FieldControl Y with he following markup (which is something we'll reach in the next paragraph) I wanted to show you what happens under the hood and why we need to do some of these things that will follow.
I. How does Sitefinity load the FieldControls when you're using the custom template option?
When we're in custom template mode Sitefinity loads all controls through the Container. Simple as that:
, Control> FieldControls
If your control is not in this collection, the story ends here - it will be displayed as markup, but Sitefinity is not going to bind any data to it, nor is it going to persist any input. This immediately gives us two prerequisites that should be fulfilled in order for Sitefinity to start working with your controls:
1. They should be assignable from the FieldControl type. You already know most of these guys - TextField, HtmlField, DateField, ChoiceField, Flat/HierarchicalTaxonField, ImageField ...you get it.
2. They should have an ID in the markup. In order for the Container to include a control in its collection it should have an ID attribute. The ID can be anything, the only prerequisite here is to ensure there's not another control on the template with the same ID.
II. How does Sitefinity bind data to the FieldControls on the template?
Once the collection is initialized, for each FieldControl Sitefinity attempt at finding the corresponding property from the selected UserProfile type and will read its value for the particular user:
BindControl(Control control, UserProfile detailItem)
var fieldControl = control
//Skip field controls that do not have DataFieldName configured
value = detailItem.GetValue(fieldControl.DataFieldName);
fieldControl.Value = value;
var requiresDataItemField = fieldControl
requiresDataItemField.DataItem = detailItem;
Notice the comment above - "Skip field controls that do not have DataFieldName configured". Yes, that's the third requirement you should fulfill.
3. In order for Sitefinity to know which property form the UserProfile type to bind to which FieldControl, it needs the DataFieldName attribute to be set in your markup. DataFieldName is pretty self-explanatory - the name of the property you have defined on your UserProfile. For example if you have created custom field called "MyField1", DataFieldName is exactly that - "MyField1". Think of this as if you're working with the CustomFields API in Sitefinity - in order to get the value of a custom field you call GetValue("FieldName").
4. As we're talking about the Write mode of the UserProfile widget we should always specify DisplayMode="Write" for each FieldControl. I assume the audience of this post varies greatly - from business folks, through content editors and designers to developers. Some of you might be better acquainted with the FieldControl implementation in Sitefinity, some not. Either ways what you need to know is that a Field control can change its behavior depending on whether it's in Read or Write mode. This is specified through the DisplayMode property. When you want to only display data you switch the FieldControl to DisplayMode="Read". When you want to facilitated user input you switch it to DisplayMode="Write".
Enough theory. Before we move on to some practical examples let's quickly summarize the gathered requirements. Each control you add on your UserProfile widget Write mode template should:
1. Be assignable from FieldControl type
2. Have an ID property
3. Have a DataFieldName property filled with the name of the property
4. Have DisplayMode="Write"
Now let's start reviewing each property type you can define for a UserProfile and the corresponding markup you should include in your template to ensure everything works correctly.
Fields of type ShortText are represented with a simple TextBox which you can type in when in Write mode, and the value is displayed in a Literal when in Read mode. This functionality is handled by the Sitefinity TextField.
When you add a field of type ShortText to your UserProfile, and then go to edit the UserProfile widget Write mode template you will see this new field appear int he list of properties you can select for inserting on the template. The markup that gets generated by default is:
Value='<%# Eval("CustomShorttextField")%>' />
Let's analyze it using the requirements we summarized above:
1. The control is of type TextField - it is assignable from FieldControl, so this requirement is OK.
2. The markup should contain an ID - this is not true, and we should correct it. For example:
3. The markup should have a DataFieldName - this is also not true. We can take the DataFieldName value from the Eval(), and add it to our markup :
4. The markup should have a DisplayMode="Write" - by default it's set to Read, so let's change it:
That's it. Now Sitefinity will be able to bind the value (if it's been populated already) of the CustomShorttextField property for the particular user's profile and display it in Write mode of the UserProfile widget. If you change the value, or type a new one, and use the ProfileWidget's Save button it will be properly persisted in the user's profile.
Fields of type LongText are represented with our Rich text editor, where you can insert much more complex content, including hyperlinks, images, etc. when in Write mode. The value is displayed in a Literal when in Read mode. This functionality is handled by the Sitefinity HtmlField.
When you add a field of type LongText to your UserProfile, and then go to edit the UserProfile widget Write mode template you will see this new field appear in the list of properties you can select for inserting on the template. The markup that gets generated by default is:
Value='<%# Eval("CustomLongTextField")%>' />
LongText fields are treated specially (and the difference int he generated markup is just the tip of the iceberg, but that's an abstraction for this post), and the generated markup properly specifies the HtmlField type. Let's see how this markup should be adjusted to suit our requirements:
1. HtmlField is of type FieldControl, so this one - OK
2. ID is missing, let's add one:
3. There's no DataFieldName - let's add one. We can use the value of the Eval(), because this is actually the field name:
4. The DisplayMode is Read. We're going to Write data into this field, so let's change it to the proper Write mode:
That's it. This markup is sufficient for Sitefinity to render the value (if any's been stored) from the user's profile in the rich text editor when in Write mode of the UserProfile widget, and store any changes made to it in the profile when you Save.
If by now you've started thinking things are getting boring, prepare yourself. MultipleChoice field types are represented with one of our quite complex FieldControls - the ChoiceField. It needs to accommodate various scenarios - check boxes, radio buttons, dropdowns. This adds some specifics to the markup we should use. Let's see how this applies to each one of them.
When you add a field of type MultipleChoice to the UserProfile you have the ability to define the choices the user can select among. Once you click on Done these choices are written in the Sitefinity configuration files as key-value pairs. The key and value are both filled with the choice text you have entered for each choice option. If you're not sure about the exact values you've entered when creating the field you can check it in App_Data/Sitefinity/Configuration/ContentViewConfig.config by searching for the field name. For example if you have a field called CustomMultipleCheckboxesField a search in the ContentViewConfig.config will return XML similar to:
"Non alphanumeric characters are not allowed."
"You have entered an invalid currency."
"You have entered an invalid email address."
"You have entered an invalid integer."
"You have entered an invalid URL."
"Alphanumeric characters are not allowed."
"You have entered an invalid number."
"You have entered an invalid percentage."
"You have entered an invalid US social security number."
"You have entered an invalid US ZIP code."
Why do we need this? Because the markup that Sitefinity will automatically generate for this field when you edit the widget template and click on the property that appears in the list of available properties is:
Value='<%# Eval("CustomMultipleCheckboxesField")%>' />
This is fine for read mode, as it will indeed display the value of the selected choice (if any), however we want to allow the users to modify their selection when in Write mode of the UserProfiles widget, thus we need to change this:
1. We need to change the TextField to ChoiceField - this is the proper FieldControl inheritor that manages MultipleChoice fields:
2. We need an ID:
3. We need a DataFieldName:
4. We need to set the DisplayMode to Write:
5. No, we're not done, yet! Remember the choices values we talked about above? We need to tell the ChoiceField control we added to our template what choices to render, and what value to persist when an option is selected and the user clicks on Save of the UserProfile widget in Write mode. For this purpose we take the choicesConfig section form the ContentViewConfig.config XML and set it as Choices option for the ChoiceField. The pattern we should follow looks like:
Which in our case gets translated to:
Value='<%# Eval("CustomMultipleCheckboxesField")%>' >
6. The final step is to specify some additional options which determine the FieldControl's behavior. If you inspect the XML entry in the ContentViewConfig.config for this field you'll notice something like:
These settings determine the field's behavior if you use "auto-generated" template mode, or if you edit the user's profile in the backend User management screen. To achieve the same experience when you're in the UserProfile widget Write mode you can add:
This property is pretty much self-explanatory - it tells the field that a user cannot select more than 1 value (even if they do only the first will be persisted).
The second, more interesting property which you need to define is the RenderChoicesAs. It determines what interface will be rendered by the ChoiceField for selecting the choices, and gives us a certain level of convenience if we want to change the input type in the UserProfile widget in Write mode. Here are the available modes you can select from:
// Choices are rendered as checkboxes.
// Choices are rendered as items of a drop down box.
// Choices are rendered as items of a list box.
// Choices are rendered as radiobuttons.
// A single checkbox for setting values to boolean properties
// Choices are rendered as horizontal radiobuttons
Note: Please mind that that the property is called RenderChoicesAs, which is the correct name that should be used on the template, while the XML config entry is for the field is saved as renderChoiceAs, don't get misled!)
So let's complete the final step and set the RenderChoicesAs in our markup:
That's it - with this markup you'll have a fully functioning ChoiceField, displaying the selected choice (if any) form the user's profile, and saving your selection in the profile when you click on Save of the UserProfile widget in Write mode.
IV. Yes / No
Having gone through MultipleChoice it will be very easy to explain what' the proper markup for Yes / No field type. This is so, because the FieldControl used for Yes / No fields is the same - ChoiceField, only with different settings.
When you add a field of type Yes / No to your UserProfile, and then go to edit the UserProfile widget Write mode template you will see this new field appear in the list of properties you can select for inserting on the template. The markup that gets generated by default is:
Value='<%# Eval("YNField")%>' />
A quick run through our checklist and it becomes:
1. Change TextField to ChoiceField which is the correct FieldControl inheritor for this field type:
2. Add an ID:
3. Add DataFieldName:
4. Change DisplayMode to Write:
5. Add the Choice definition. In the case of Yes / No fields it's only 1 choice with Value="true":
6. Finally configure the FieldControl behavior:
V. Date and Time
Fields of type Date and Time are represented with our Date and Time picker, where you can select the Date and Time values when in Write mode. The value is displayed in a Literal when in Read mode. This functionality is handled by the Sitefinity DateField.
When you add a field of type Date and Time to your UserProfile, and then go to edit the UserProfile widget Write mode template you will see this new field appear in the list of properties you can select for inserting on the template. The markup that gets generated by default is:
<sitefinity:TextField runat="server" DisplayMode="Read" Value='<%# Eval("CustomDTField")%>' />
Value='<%# Eval("CustomDTField")%>' />
Let's adjust it to work properly in Write mode:
1. Change the FieldControl to be DateField - this is the correct FieldControl inheritor that should be used in Write mode for Date and Time field types:
And you're ready - with a fully functional Date and Time picker displaying the selected value (if any) form the user's profile, and saving the user selection in the profile on clicking Save of the UserProfile widget.
Fields of type Classification are represented with our Hierarchical or Flat taxonomy selectors, where you can select the desired taxa when in Write mode. The value is displayed in a Literal when in Read mode. This functionality is handled by the Sitefinity HierarchicalTaxonField and FlatTaxonField accordingly.
When you add a field of type Classification to your UserProfile, and then go to edit the UserProfile widget Write mode template you will see this new field appear in the list of properties you can select for inserting on the template. The markup that gets generated by default for Hierarchical taxonomies (the one for Flat taxonomies is almost identical, the only difference is that the FieldControl is of type FlatTaxonField) is:
We need to run quickly through our checklist again:
1. HierarchicalTaxonField is assignable form FieldControl, so this one - OK
2. It has an ID => OK
3. Add DataFieldName (same as TaxonomyMetaFieldName):
5. Finally you might want to change the ExpandText to something more meaningful:
"Click to add some categories"
That's it - the control will render a link with the ExpandText, which when clicked in Write mode of the UserProfile widget will show the hierarchical taxon selector with the selected items (if any) and will allow your users to select the desired taxa, which will be persisted int he profile upon clicking the Save changes button of the UserProfile widget.
Fields of type Image are represented with Image selectors, where you can select the desired Image when in Write mode. The value is displayed in an Image control when in Read mode. This functionality is handled by the Sitefinity ImageField.
When you add a field of type Image to your UserProfile, and then go to edit the UserProfile widget Write mode template you will see this new field appear in the list of properties you can select for inserting on the template. The markup that gets generated by default for Hierarchical taxonomies is:
Value='<%# Eval("CustomImgFld")%>' />
A quick tun through our checklist again:
1. The FieldControl should be ImageField:
3. Add a DataFieldName (same as the value int he Eval() call):
5. Configure the additional properties determining the ImageField behavior:
a) The DataFieldType should always be Telerik.Sitefinity.Model.ContentLinks.ContentLink - this is the internal type of the property that gets persisted, so take the above sample as granted.
b) Same goes for the UploadMode - always use InputField
c) The SizeInPx is used to scale down the uploaded image when the ImageField is in Write mode (it does not resize the actual uploaded image)
d) The ShowDeleteImageButton property determines whether the ImageField in Write mode should render a button allowing the user to delete the upload image, thus setting a "null" value for this property.
With the above markup configuration you'll have your Image field displaying the selected image (if any) and allowing you to modify the image when using the UserProfile widget in Write mode. The changes will be reflected in the user's profile upon clicking the Save changes button.
VIII. Currency, Number, and some others
Why do we group these under one section? The answer is quite simple - the FieldControl these field types use for displaying/editing the property value is again a TextField, so everything that applies to point I. TextField is valid in these cases as well. The only additional configuration you need to do concerns validating the user input to ensure it corresponds to the particular format.
To put it shortly, whether you add a Currency or Number field to your UserProfile, when you go to edit the UserProfile widget template in Write mode, Sitefinity will insert the same markup as for a TextField:
From then on you'll need to apply the same steps as outlined in I. TextField . At the end you should have markup similar to:
Now comes the interesting part. In Sitefinity you can use the ValidatorDefinition, which under the hood works together with the FieldControl to perform server-side validation for the predefined format. So for the sake of our sample if we have added a Number field to our UserProfile and want to add this field on the UserProfile widget Write mode template we need to adjust the above markup:
Value='<%# Eval("CustomShorttextField")%>' >
And that's it - now if you try putting a value different than number when you edit a profile form the UserProfile widget, and click on Save changes the validator will inform you that only Numbers are allowed int his field.
The ValidatorDefinition has several other quite useful ExpectedFormat values which are available to use out of the box for you to use in the above demonstrated fashion, depending on the use case scenario. Here's the full list of them:
// none by default
None = 0,
// Validates alpha numerics
// Validates currency
// Validates email addresses
// Validates integers
// Validates internet urls
// Validates non aplhanumerics
// Validates numerics
// Validates percentages
// Validates US social security numbers
// Validates US zip codes
// Validates against custom regular expression
If you chose to use the last option - Custom, you can actually supply your own Regular Expression to validate the field input, for example:
As a conclusion I wanted to wrap things up in a sample "cheat sheet" which you can refer to if you don't want to go into that much details. The below table lists the Field type you have added to your UserProfile and the sample corresponding markup which you can use on your UserProfile widget Edit mode template in order to facilitate editing the corresponding property value on the user's profile:
That's about it, folks, I really hope this post serves as a helpful resource in giving you the freedom to customize your UserProfile widget Edit mode templates, and achieving the desired use case scenarios with the help of Sitefinity out of the box functionality.
As always we remain open to always trying to help you in case you need any additional information or have further questions. Please don't hesitate to get in touch through the official Support channel for any specific requests, or post us a comment for this blog.
Boyan Barnev is a Principal Information Developer at Progress. His mission is to demonstrate the unlimited capabilities of Sitefinity CMS via product documentation, SDK samples, and technical blog posts. He has graduated from the American University in Bulgaria and joined Telerik in 2011. Since then Boyan has held various positions in the company, leading the strategy and operation of the Sitefinity CMS Technical support service worldwide.
Subscribe to get all the news, info and tutorials you need to build better business apps and sites
Copyright © 2019 Progress Software Corporation and/or its subsidiaries or affiliates.
All Rights Reserved.
Progress, Telerik, and certain product names used herein are trademarks or registered trademarks of Progress Software Corporation and/or one of its subsidiaries or affiliates in the U.S. and/or other countries. See Trademarks for appropriate markings.