Custom modules: place a drop down list on edit form

Posted by Community Admin on 05-Aug-2018 13:40

Custom modules: place a drop down list on edit form

All Replies

Posted by Community Admin on 20-Jan-2011 00:00

Hello,

I need to manage specific content and, to do this, I develop a sitefinity custom module.
I'd like to know how I can display on my Edit form a drop down list with some data coming from another data table ?

Here are my needs :

This specific content is IT Interventions. An intervention is defined by a name and a date. An intervention has a state (scheduled, started, finished).

To apply a state to an intervention, in my module I have an InterventionItem class and a StateItem class.

In the InterventionItem class, I declare the relation between Intervention and States like this:

public StateItem
    get return this._stateItem;
    set this._stateItem = value,
  
private StateItem _stateItem;

In the StateItem class, I declare the relation between Intervention and States like this:
public IList<Interventions>
    get return this._interventions ;
    set this._interventions = value,
  
private List<Interventions>;

Is that the right way to declare the 1 to many relation between interventions and state?

I cannot use Custom fields because my state has others properties (not only a title).

So, on the edit form, I want to display these states in a list. In standard asp.net, I will use a DropDownList.

I see in the developer's guide, there is a "FlasTaxonFieldDefinitionElement" class in the "Telerik.Web.UI.Fields.Config". Can I use this? Can you provide me a sample to declare it on the form?

Best regards,

Posted by Community Admin on 25-Jan-2011 00:00

Hello jocelyn,

There are 2 way you can currently implement this if you build your backend UI with the config element defintions, as the other sitefinity modules aer built including the Products SDK sample module. Check the ProuductDefinitions.cs

1)ChoiceField control

- You have to hard code the possible choices in the definition.

var selectSizeElement = new ChoiceFieldElement(defaultImgSizeSection.Fields)
            
                ID = "SelectStateFieldControl",
                DataFieldName = "State",
                DisplayMode = FieldDisplayMode.Write,
                MutuallyExclusive = false,
                RenderChoiceAs = RenderChoicesAs.DropDown,
                FieldType = typeof(ChoiceField)
            ;
            selectSizeElement.ChoicesConfig.Add(new ChoiceElement(selectSizeElement.ChoicesConfig)
                                                
                                                    Text = "Scheduled",
                                                    Value = "0"
                                                );
            selectSizeElement.ChoicesConfig.Add(new ChoiceElement(selectSizeElement.ChoicesConfig)
                                                
                                                    Text = "Started",
                                                    Value = "1"
                                                );
            selectSizeElement.ChoicesConfig.Add(new ChoiceElement(selectSizeElement.ChoicesConfig)
                                                
                                                    Text = "Finished",
                                                    Value = "2"


2)HierarchicalTaxonField

You have to install a taxonomy in the module installation and than point to this taxonomy into the the field defintion. The good thing about taxonomy is that the item titles in the taxonomy can be localized and there is also statistics how many content items you have per taxon.

new HierarchicalTaxonFieldDefinitionElement(section)
ID = "categoriesFieldControl", dataFieldName = "Category", DisplayMode = FieldDisplayMode.Write, ResourceClassId = typeof(TaxonomyResources).Name, TaxonomyId = TaxonomyManager.CategoriesTaxonomyId, WebServiceUrl = "~/Sitefinity/Services/Taxonomies/HierarchicalTaxon.svc", AllowMultipleSelection = true,WrapperTag = HtmlTextWriterTag.Li, Title = "Categories", ExpandableDefinitionConfig =Expanded = false,ExpandText = "ClickToAddCategories",ResourceClassId = typeof(TaxonomyResources).Name


You can replace the TaxonomyManager.CategoriesTaxonomyId, with th Id of your custom taxonomy with the 3 taxons for  scheduled, started, finished.

To install the custom taxonomy during the installation of your module. You have to use the TaxonomyManager to create and add new taxonomy and related taxons plus add the taxonomy field to your content type. If you inherit ContentModuleBase the easiest is to override the InstallTaxonomies method and use a code like this

===add the new taxonomy
var flatTaxonomy = this.GetOrCreateTaxonomy<FlatTaxonomy>(initializer, "States", MyStatesTaxonomyID, Res.Get<ContentResources>().Tag);
flatTaxonomy
==add code to add the required taxons for the states
 
=== add the taxonomy field to your type
var metaMan = initializer.Context.MetadataManager;
var type = metaMan.CreateMetaType(yourType);
field = metaMan.CreateMetafield("StatesField");
field.TaxonomyProvider = taxMan.Provider.Name;
field.TaxonomyId = MyStatesTaxonomyID;
field.IsSingleTaxon = trie;
type.Fields.Add(field);



Kind regards,

Nikolay Datchev
the Telerik team


Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Posted by Community Admin on 25-Jan-2011 00:00

Hello Nikolay,

Thanks for your answer.

Regarding the ChoiceField control, there is no way to bind it to another datatable doing some thing like this:

var selectSizeElement = new ChoiceFieldElement(defaultImgSizeSection.Fields)
            
                ID = "SelectStateFieldControl",
                DataFieldName = "State",
                DisplayMode = FieldDisplayMode.Write,
                MutuallyExclusive = false,
                RenderChoiceAs = RenderChoicesAs.DropDown,
                FieldType = typeof(ChoiceField),
                ServiceBaseUrl = "Sitefinity/Services/Content/States.svc"
            ;

Another solution (very bad) is to get the states list, browse the states with a for each and create a choice field for each state and add it to the choicefieldelement.

==add code to add the required taxons for the states
Under this comment, I can add some validators?

I have some questions about this part of your code:
=== add the taxonomy field to your type
var metaMan = initializer.Context.MetadataManager;
var type = metaMan.CreateMetaType(yourType);
field = metaMan.CreateMetafield("StatesField");
field.TaxonomyProvider = taxMan.Provider.Name;
field.TaxonomyId = MyStatesTaxonomyID;
field.IsSingleTaxon = trie;
type.Fields.Add(field);

What is the type of the variable yourType?
Can this new type have more than one field?
Which types or fields are available? Can a field be an image?

A state is defined by a name (United states, France...) and a flag (an image). Can this model be implement using taxonomies?

From the edit form of our product catalog, we must be able to set the availibility of a product in the world.

Or should we develop our own field element?

Jocelyn

Posted by Community Admin on 28-Jan-2011 00:00

Hello jocelyn payneau,

I will try to answer to your questions here one buy one:
What is the type of the variable yourType?
It is the type which will be classified with the taxonomy,e.g. if an intervention is classified with scheduled/started/finished. Than we need to add a taxonomy field to the Intervention class. So yourType would be typeof(Intervention).
Can this new type have more than one field?
This is not a new type, it is the type that you want to classify. You can have your fields declared in the type in your code. You can also add as many dynamic fields to it, and hence you can add more than one taxonomy to it, by adding several taxonomy fields.
Which types or fields are available? Can a field be an image?
Currently we don't natively support adding an image field.

A state is defined by a name (United states, France...) and a flag (an image). Can this model be implement using taxonomies? 
For example you can make use of some kind of convention. Let's say you want to have the flag of United States -> You can have an Image Library - called StateFlags and add images with the same Title as the Country title. Later you can find  the image that you want to show on the front-end by the name of the State that is persisted with your item.

From the edit form of our product catalog, we must be able to set the availability of a product in the world.
Or should we develop our own field element?

Just to say, that developing a backend UI for your module has not to be done necessarily with our field controls(elements) if your backend scenarios require too much customizations. You can make your own entirely Custom or User Control and add to the Controls collection of the Backend Page you install with the Module.

On the other hand doing a new field element is also a viable option - you can probably inherit the ChoiceField - and pre-populate it on the server with the items from the taxonomy.  It needs though to have a TaxonomyId property so you can specify from which taxonomy it is going to populate. Btw - every field element- actually has a property FieldType  - where you can specify your own custom FieldType.
So for examle you can use the TaxonFieldDefinitionElement, but put in FieldType -> your own custom control type that inherits ChoiceField and completely overrides the following method.

public override void Configure(IFieldDefinition definition)

In this method the control, reads the element defintion and gets populated from the chocies, in your case it can get populated from the taxonomy, - which is perfectly ok. You just have to cast the defintion to ITaxonFieldDefinition, so you can get the TaxnomyId and use Taxonomy API to get the taxons data. (TaxonomyManager)

Using this approach you could also actually pre-populate your ChoiceField not from a taxonomy but from the records of a custom type States, etc.

Nikolay Datchev
the Telerik team


Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Posted by Community Admin on 01-Feb-2011 00:00

Hello Nikolay,

I create a new class DropDownListField inherited from ChoiceFIeld.

I override the method Configure like this:

public override void Configure(IFieldDefinition definition)
        
            var tManager = TaxonomyManager.GetManager();
  
            var taxonomy = tManager.GetTaxonomies<FlatTaxonomy>().Where(t => t.Name == "Countries").Single();
  
            var countries = taxonomy.Taxa.OrderBy(c => c.Title.ToString());
  
            this.RenderChoicesAs = Telerik.Sitefinity.Web.UI.Fields.Enums.RenderChoicesAs.DropDown;
  
              
        

I add a new definition like this:
var ddlField = new TaxonFieldDefinitionElement(mainSection.Fields)
            
                ID = "ddlFIeldControl",
                AllowMultipleSelection = false,
                DataFieldName = "country_id",
                FieldType = typeof(DropDownListField),
                WrapperTag = HtmlTextWriterTag.Li
            ;
  
            mainSection.Fields.Add(ddlField);

When a click the Create button to open the insert form, I have an asp.net error page with this message:
Invalid resource name "Telerik.Sitefinity.Resources.Templates.Fields.ChoiceField.ascx" for assembly "Contacts, Version=1.0.4049.23058, Culture=neutral, PublicKeyToken=null" or empty template.

Thanks,
Jocelyn

Posted by Community Admin on 01-Feb-2011 00:00

Hello jocelyn payneau,

This is actually a problem with how our embedded ascx control templates are resolved. Since you inherit this control in a new assembly, the template resolver cannot guess where to get the template from(using the LayoutTemplateName). So you need to explicitly override the method ResourcesAssemblyInfo of the ChoiceField and return Config.Get<ControlsConfig>().ResourcesAssemblyInfo. Which is basically saying to sitefinity that it needs to lookup the tempalte in our main resources assembly, not in yours. This problem is scheduled to be fixed soon, so the LayoutTemplateName location is not ambiguous. Sorry for the inconvenience.

About the configure method - you still need to fill the Choices collection manually from the taxonomy that you have read, somehing like...

public override void Configure(IFieldDefinition definition)

====first===
put your taxonomy retrieval code here.It is better to get the taxonomyid from the defintion - rather than hard-coding "Countries" -since you can reuse your control for other taxonomies too.
say: var taxonDefintion = defintion as ITaxonFieldDefinition;
var taxonomyId = defintion.TaxonomyId
you can have some kind of well known constant Guid for your taxonomy id, and set this when you create the definition element
====next==
this.Choices.Clear();
foreach (var taxon in countries)  
    var choice = new ChoiceItem();
    choice.Value = taxon.Id.ToString();
    choice.Text = taxon.Title;
    this.Choices.Add(choice);


Regards,

Nikolay Datchev
the Telerik team


Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Posted by Community Admin on 02-Feb-2011 00:00

Hello,

I hard coding only to make some tests. It will be dynamic once it works.

Overriding the ResourcesAssemblyInfo method solve the asp.net error.

But when I create a new item, the insert form is broken and I have a JavaScript error "Contact is undefined":

Sys.Application.add_init(function()
    $create(Contacts.Web.UI.DropDownListField, "_mutuallyExclusive":false,"_renderChoicesAs":0,"_selectedChoicesIndex":null,"choices":["Text":"France","Value":"c21c18ad-08b7-460f-ba82-0fd84df8acc6","Description":null,"Enabled":false,"Selected":false,"Text":"United States","Value":"7f5adb3b-d3b1-430b-9a3d-ac46c3829a45","Description":null,"Enabled":false,"Selected":false],"controlErrorCssClass":null,"dataFieldName":null,"dataFormatString":null,"description":null,"descriptionElement":$get("ctl04_ctl00_contentView_ctl00_ctl00_sections_section_0_ctl00_0_fields_0_ctl00_2_ctl00_2_descriptionLabel_2"),"displayMode":0,"example":null,"exampleElement":$get("ctl04_ctl00_contentView_ctl00_ctl00_sections_section_0_ctl00_0_fields_0_ctl00_2_ctl00_2_exampleLabel_2"),"readModeLabel":$get("ctl04_ctl00_contentView_ctl00_ctl00_sections_section_0_ctl00_0_fields_0_ctl00_2_ctl00_2_read_2"),"title":null,"titleElement":$get("ctl04_ctl00_contentView_ctl00_ctl00_sections_section_0_ctl00_0_fields_0_ctl00_2_ctl00_2_titleLabel_2"),"validatorDefinition":"\"AlphaNumericViolationMessage\":\"Non alphanumeric characters are not allowed.\",\"ComparingValidatorDefinitions\":[],\"CurrencyViolationMessage\":\"You have entered an invalid currency.\",\"EmailAddressViolationMessage\":\"You have entered an invalid email address.\",\"ExpectedFormat\":0,\"IntegerViolationMessage\":\"You have entered an invalid integer.\",\"InternetUrlViolationMessage\":\"You have entered an invalid URL.\",\"MaxLength\":0,\"MaxLengthViolationMessage\":\"Too long\",\"MaxValue\":null,\"MaxValueViolationMessage\":\"Too big\",\"MessageCssClass\":null,\"MessageTagName\":\"div\",\"MinLength\":0,\"MinLengthViolationMessage\":\"Too short.\",\"MinValue\":null,\"MinValueViolationMessage\":\"Too small.\",\"NonAlphaNumericViolationMessage\":\"Alphanumeric characters are not allowed.\",\"NumericViolationMessage\":\"You have entered an invalid number.\",\"PercentageViolationMessage\":\"You have entered an invalid percentage.\",\"RegularExpression\":null,\"RegularExpressionViolationMessage\":\"Ivalid format.\",\"Required\":null,\"RequiredViolationMessage\":\"Required field.\",\"USSocialSecurityNumberViolationMessage\":\"You have entered an invalid US social security number.\",\"USZipCodeViolationMessage\":\"You have entered an invalid US ZIP code.\",\"ValidateIfInvisible\":true","value":null, null, null, $get("ctl04_ctl00_contentView_ctl00_ctl00_sections_section_0_ctl00_0_fields_0_ctl00_2"));
);

Please see a screenshot attached to the post.

Thanks
Jocelyn

Posted by Community Admin on 02-Feb-2011 00:00

Hello jocelyn,

Ok, seems like the next thing i missed to mention. I really hope this to be the last blocker, and i guess we have to publish your case as a good sample for the other customers, how to inherit our field controls.
The problem here seems to be related with the fact that we automatically assume that there is a client side javascript component with the name as your field control class. But since you don't want to change anything in the client side behavioral of choiceField, you can still use the base js component. In order to achieve this you should override the ScriptDescriptorTypeName method and return typeof(ChoiceField).FullName. I hope this helps.

Greetings,
Nikolay Datchev
the Telerik team


Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Posted by Community Admin on 03-Feb-2011 00:00

Hello Nikolai,

It does not solve the problem. I still have the javascript error.

Here is my Dropdownlistfield class code:

namespace Contacts.Web.UI
    public class DropDownListField : ChoiceField
    
        protected override Type ResourcesAssemblyInfo
        
            get
            
                return Config.Get<ControlsConfig>().ResourcesAssemblyInfo;
            
        
  
        protected override string ScriptDescriptorTypeName
        
            get
            
                return typeof(ChoiceField).FullName;
            
        
  
        public override void Configure(IFieldDefinition definition)
        
            var tManager = TaxonomyManager.GetManager();
  
            var taxonomy = tManager.GetTaxonomies<FlatTaxonomy>().Where(t => t.Name == "Countries").Single();
  
            var countries = taxonomy.Taxa.OrderBy(c => c.Title.ToString());
  
            this.Choices.Clear();
            foreach (var taxon in countries)
            
                var choice = new ChoiceItem();
                choice.Value = taxon.Id.ToString();
                choice.Text = taxon.Title;
                this.Choices.Add(choice);
            
        
    

It seems the namespace "Contacts.Web.UI.DropDownListField" cannot be found or resolved. Can you confirm this?

Another point: if my drop down list should be filled with some custom content types, I can do some code like this:
var statesManager = StatesManager.GetManager(); 
    
var states = statesManager.GetStates();
this.Choices.Clear(); 
foreach (var state in states)  
 
var choice = new ChoiceItem(); 
choice.Value = state.Id.ToString(); 
choice.Text = state.Title; 
this.Choices.Add(choice); 
 

It is very important this feature works perfectly at least by the end of the week. It is critical for my project.

Thanks
Jocelyn

Posted by Community Admin on 03-Feb-2011 00:00

Hi jocelyn payneau,

I attached a control that will do the trick. It seems that ScriptDescriptorTypeName is not considered , which  is a bug which we are going to fix, but i am sending you a workaround here. You should use the following definition:

var dropDownTaxonomyField = new TaxonFieldDefinitionElement(mainSection.Fields)
ID = "testTaxonomyField",
Title = Res.Get<ProductsResources>().lTitle,
DataFieldName = "Tags",
TaxonomyId = TaxonomyManager.TagsTaxonomyId,
FieldType = typeof(TaxonomyDropDownField),
ResourceClassId = typeof(ProductsResources).Name,
DisplayMode = displayMode,
;
mainSection.Fields.Add(dropDownTaxonomyField);

In general this control will work fine for the drop-down scenario with single item taxonomy. The multiple checkbox scenario though has a problem that if only one item is checked - it cannot save the value correctly since the choicefield control doesn't return an array of choices in the javascript component, so we will need to also inherit the javascript component of the ChoiceField class . I will provide this inherited js additionally. I will try to do this tomorrow. I assume that you will also need the code to install your custom taxonomy. I  had some problems reproducing this  today, which can be related to some bug that we have, so I will keep investigating this tomorrow. If this is a bug most probably i will provide a fix in the Friday's build.

Greetings,

Nikolay Datchev
the Telerik team


Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Posted by Community Admin on 04-Feb-2011 00:00

Hi Nikolay,

It works!

I managed to display the countries list.

I also managed to display some contents from a custom module I develop (based on the product catalog sample). This module allows to manage some parameters of a product (i.e Diameters). A diameter is defined by a title and an image. I managed to display diameters title in a drop down on my edit form. But the association between a product and a diameter is not saved.

Here is the piece of code which declare the model:

[DataMember]
        public DiameterItem Diameter
        
            get
            
                return this.diameter;
            
            set
            
                this.diameter= value;
            
        
  
private DiameterItem diameter;

Did I miss to do something to implement the one-to-many relation between a product and a diameter so that open access will update the model in the database?

Thanks

Jocelyn

Posted by Community Admin on 04-Feb-2011 00:00

Hi jocelyn ,

Currently i am afraid we can not manage such associations through the Edit Form. We do this only for taxonomies. What i would suggest as a workaround is to  have only the DiameterId field , so you field control is bound to the "DiameterId" (Guid or int - whatever is your key). The association can be implemented additionally in your Data Provider. For example you can have GetProductDiameterByID method in your manager/provider.

Greetings,
Nikolay Datchev
the Telerik team


Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Posted by Community Admin on 04-Feb-2011 00:00

Hello Nikolai,

Thanks for your reply.

I add in my model class (ProductItem.cs) this code:

[DataMember]
        public Guid DiameterId
        
            get return this.diameterId;
            set this.diameterId= value;
        
        private Guid diameterId;

in the view model class, I add this code in the constructor
public ContactItemViewModel(ContactItem contentItem, ContentDataProviderBase provider)
            : base(contentItem, provider)
         

                ... // my other fields
            this.LocationId = contentItem.LocationId;

When i run my website the field DiameterId is not added in the product table when module is updating.

Thanks
Jocelyn

Posted by Community Admin on 04-Feb-2011 00:00

Hello jocelyn,

I think this is related with the db upgrade algorithm of Sitefinity. To initiate db upgrade It checks for a part of the build number of the custom module assembly, which is actually the same during all builds in the same day. So i would suggest to go with  a blank installation of sitefinity,  with  a new database, or manually change this number to a lower number in the builds tracking table - sf_schema_versions - column version_number.  Just type a lower number than the current. you see. Then restart Sitefinity by making a dummy change in the web.config, it will read the schema information - see that your assembly build has changed and force an upgrade. I really hope this will fix your problem.

Kind regards,
Nikolay Datchev
the Telerik team


Check out Telerik Trainer, the state of the art learning tool for Telerik products.

Posted by Community Admin on 22-Feb-2012 00:00

Hi Nikolay,

I tried the code you posted for a subclass of ChoiceField using it as a control on a form (registered it in the FormControls Toolbox and added it to the form). But there seems nothing to happen: the code in the Configure() method doesn't fire. Is the behaviour of controls different when added to a form? What control can I use to create dynamically added choices to a form?

Thanks for a reply (I know the original post is more than a year old),
alf borrmann

Posted by Community Admin on 05-Mar-2012 00:00

Hello,

The Configure(IFieldDefinition definition) method is called when the field control is created from definition, which is not the case if the control is added to a form.
It will be better if you use InitializeControls(GenericContainer container) to add dynamically choices.

Regards,
Vlad
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

This thread is closed