More in this section
Categories
Bloggers
Blogs RSS feed

Creating Dynamic Module Items Using the Module Builder API

by Josh Morales

We previously looked at how you can retrieve dynamic module items using the Module Builder API. Today we'll take a look at how you can use that same API to also create new items.

Using the sample code from the Code Reference (generated for every dynamic module you create) you can easily develop a new public widget that allows your site visitors to create items. Because dynamic module items support the Content Lifecycle, you can prevent these items from being published before they are reviewed.

For this example, we will once again be using the Showcases module example that Gabe created and has available on the Module Builder Webinar notes.

Submit Showcases Widget

Because Sitefinity widgets are simply user controls, all we really need to do is create a new User Control and add our input markup plus the backing code to write that data to the API. Start with the frontend of the User Control:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SubmitShowcase.ascx.cs" Inherits="SitefinityWebApp.Modules.Showcases.SubmitShowcase" %><%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI.Fields" TagPrefix="sf" %><div class="sfShowcaseSubmitForm"> <p>Do you have a website you would like us to feature? Submit it below!</p> <div> <label for="Title" class="txtLbl">Company or Website Name</label> <asp:TextBox ID="Title" ClientIDMode="Static" runat="server" /> </div> <div> <label for="SiteUrl" class="txtLbl">Site Url</label> <asp:TextBox ID="SiteUrl" ClientIDMode="Static" runat="server" /> </div> <div> <label for="LaunchDate" class="txtLbl">Launch Date</label> <telerik:RadDatePicker ID="LaunchDate" runat="server" ClientIDMode="Static" /> <div> <label for="Industries" class="txtLbl">Industry</label> <asp:DropDownList ID="Industries" ClientIDMode="Static" runat="server" /> </div> <div> <label class="txtLbl">Case Study Features</label> <asp:CheckBoxList ID="FeaturesList" ClientIDMode="Static" runat="server" RepeatColumns="4" RepeatDirection="Horizontal" RepeatLayout="Table" /> </div> <div> <label for="Countries" class="txtLbl">Country</label> <asp:DropDownList ID="Countries" ClientIDMode="Static" runat="server" /> </div> <div> <label>Sitefinity Version</label> <asp:RadioButtonList ID="Version" runat="server"> <asp:ListItem Text="Sitefinity 3.x" Value="Sitefinity 3.x" /> <asp:ListItem Text="Sitefinity 4.x" Value="Sitefinity 4.x" /> </asp:RadioButtonList> </div> <div> <label for="Thumbnail" class="txtLbl">Website Screenshot</label> <telerik:RadUpload ID="Thumbnail" ClientIDMode="Static" runat="server" AllowedFileExtensions=".gif,.jpg,.jpeg,.png" MaxFileInputsCount="1" InputSize="45" ControlObjectsVisibility="None" /> <div> <label for="CaseStudy" class="txtLbl">Case Study (PDF)</label> <telerik:RadUpload ID="CaseStudy" ClientIDMode="Static" runat="server" AllowedFileExtensions=".pdf" MaxFileInputsCount="1" InputSize="45" ControlObjectsVisibility="None" /> <div> <label for="Content" class="txtLbl">Case Study</label> <sf:FormManager ID="formManager" runat="server" /> <sf:HtmlField ID="Content" ClientIDMode="Static" runat="server" Width="99%" Height="370px" DisplayMode="Write" FixCursorIssue="True" /> </div> <div> <asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="Submit" /> </div> <telerik:RadInputManager ID="RadInput" runat="server"> <telerik:RegExpTextBoxSetting ValidationExpression="http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&amp;=]*)?" ClearValueOnError="false"> <TargetControls> <telerik:TargetInput ControlID="SiteUrl" /> </TargetControls> </telerik:RegExpTextBoxSetting> <telerik:TextBoxSetting Validation-IsRequired="true"> <TargetControls> <telerik:TargetInput ControlID="Title" /> <telerik:TargetInput ControlID="SiteUrl" /> <telerik:TargetInput ControlID="LaunchDate" /> <telerik:TargetInput ControlID="Content" /> </TargetControls> </telerik:TextBoxSetting> </telerik:RadInputManager> </div> </div> </div></div>

This is simply a collection of input controls to collect the data from the user that corresponds to the fields for our dynamic content type. For simplicity, we've excluded validation controls.

Choice Fields

In the current version of Sitefinity (4.4 as of today), choice fields used by the module do not yet persist the valid list of items anywhere other than on the backend sitefinity forms that are created by the module. As a result, it is not yet possible to automatically bind input controls such as dropdown menus and radio buttons to those choices, but instead must be manually populated.

This is what we have done in the code above for the Sitefinity Version field, and explicitly defined the valid choices for our module.

Future versions of the module builder will address this so that you can access these choices and bind to them automatically.

Code-Behind: On Control Load

Although we cannot bind to choice fields automatically, there are some controls we can load automatically using the regular Sitefinity API. Specifically we can pre-load the Taxonomy fields for Industry, Features, and Countries.

For this I've defined a helper method that will retrieve the list taxon items for a taxonomy based on the name of the parent taxonomy title.

private IEnumerable<ITaxon> GetTaxonomy<TTaxonomy>(string TaxonomyName) where TTaxonomy : class, ITaxonomy{
    // bind categories selector var taxMgr = TaxonomyManager.GetManager();
    var taxonomy = taxMgr.GetTaxonomies<TTaxonomy>().Where(t => t.Title == TaxonomyName).FirstOrDefault();
    if (taxonomy == null) return null;

    // return taxa items var taxa = taxonomy.Taxa;
    return taxa;
}

Now we can simply call that helper method on the Page_Load event so that our taxonomy controls are loaded and bound.

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack) return;

    // bind Industries menu foreach (var industry in GetTaxonomy<HierarchicalTaxonomy>("Industries"))
    {
        var item = new ListItem(industry.Title, industry.Id.ToString());
        Industries.Items.Add(item);
    }

    // bind features selectors foreach (var feature in GetTaxonomy<FlatTaxonomy>("Features"))
    {
        var chk = new ListItem(feature.Title, feature.Id.ToString());
        FeaturesList.Items.Add(chk);
    }

    // bind countries selectors foreach (var country in GetTaxonomy<FlatTaxonomy>("Countries"))
    {
        var item = new ListItem(country.Title, country.Id.ToString());
        Countries.Items.Add(item);
    }
}

Code-Behind: On Submit

Once the user completes the form and submits it, we want to save that data into a new dynamic module item. Because we have media fields in our content model, we need to first support uploading of media to the Sitefinity Images and Documents modules. This is done with helper methods of each type that write the file contained in a RadUpload control to the database.

protected Telerik.Sitefinity.Libraries.Model.Image UploadImage(RadUpload radUploader, string title)
{
    Telerik.Sitefinity.Libraries.Model.Image img = null;
    if (radUploader.UploadedFiles.Count == 0) return img;

    // select showcases album var imgMgr = LibrariesManager.GetManager();
    var album = imgMgr.GetAlbums().Where(a => a.Title == "Showcase Screenshots").FirstOrDefault();
    
    // prepare transaction using (var sf = App.Prepare().SetTransactionName("UploadTransaction").WorkWith())
    {
        // temporarily disable security checks to allow image creation without login sf.Images().GetManager().Provider.SuppressSecurityChecks = true;

        // save image properties img = imgMgr.CreateImage();
        img.Parent = album;
        img.Title = title;
        img.UrlName = title + "_Screenshot";
        img.Status = Telerik.Sitefinity.GenericContent.Model.ContentLifecycleStatus.Master;

        // upload Image var file = radUploader.UploadedFiles[0];
        imgMgr.Upload(img, file.InputStream, file.GetExtension());
        imgMgr.Publish(img);
        imgMgr.SaveChanges();

        // re-enable security sf.Images().GetManager().Provider.SuppressSecurityChecks = false;
    }

    // return image so it can be associated with module content item return img;
}

protected Telerik.Sitefinity.Libraries.Model.Document UploadDocument(RadUpload radUploader, string title)
{
    Telerik.Sitefinity.Libraries.Model.Document doc = null;
    if (CaseStudy.UploadedFiles.Count == 0) return doc;

    // select showcases album var docMgr = LibrariesManager.GetManager();
    var album = docMgr.GetDocumentLibraries().Where(a => a.Title == "Showcase Case Studies").FirstOrDefault();

    // prepare transaction using (var sf = App.Prepare().SetTransactionName("UploadTransaction").WorkWith())
    {
        // temporarily disable security checks to allow image creation without login sf.Documents().GetManager().Provider.SuppressSecurityChecks = true;

        // save image properties doc = docMgr.CreateDocument();
        doc.Parent = album;
        doc.Title = title;
        doc.UrlName = title;
        doc.Status = Telerik.Sitefinity.GenericContent.Model.ContentLifecycleStatus.Master;

        // upload Image var file = radUploader.UploadedFiles[0];
        docMgr.Upload(doc, file.InputStream, file.GetExtension());
        docMgr.Publish(doc);
        docMgr.SaveChanges();

        // re-enable security sf.Documents().GetManager().Provider.SuppressSecurityChecks = false;
    }

    // return image so it can be associated with module content item return doc;
}

Finally, we simply go through each field and map the simple properties (text, datetime, boolean, etc) using the SetValue() extension method.

NOTE: be sure to include the using Telerik.Sitefinity.Model namespace to use this extension method.

public void Submit(object sender, EventArgs e)
{
    // initialize the dynamic module content manager DynamicModuleManager mgr = DynamicModuleManager.GetManager();
    

    // initialize a new [ModuleItem] Type showcaseType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.Showcases.Showcase");
    DynamicContent showcaseItem = mgr.CreateDataItem(showcaseType);

    // save simple fields to the item var title = Title.Text.Trim();
    showcaseItem.SetValue("Title", title);
    showcaseItem.SetValue("SiteUrl", SiteUrl.Text);    
    showcaseItem.SetValue("LaunchDate", LaunchDate.SelectedDate);
    showcaseItem.SetValue("UrlName", new Lstring(title.Replace(" ", "-"))); // TODO: use regex to strip characters showcaseItem.SetValue("Content", Content.Value.ToString());
    showcaseItem.SetValue("Platform", new string[] { Version.SelectedValue });

    // save selected country showcaseItem.Organizer.AddTaxa("countries", new Guid(Countries.SelectedValue));

    // save selected category showcaseItem.Organizer.AddTaxa("industries", new Guid(Industries.SelectedValue));

    // save selected tags foreach (ListItem tag in FeaturesList.Items)
        if (tag.Selected) showcaseItem.Organizer.AddTaxa("features", new Guid(tag.Value));

    // save thumbnail if present var img = UploadImage(Thumbnail, title);
    if (img != null)
    {
        var contentLink = new ContentLink(img.Parent.Id, img.Id);
        var screenshots = new List<ContentLink>() { contentLink };
        showcaseItem.SetValue("Screenshot", screenshots.ToArray());
    }

    // save document if present var doc = UploadDocument(CaseStudy, title);
    if (doc != null)
    {
        var contentLink = new ContentLink(doc.Parent.Id, doc.Id);
        var screenshots = new List<ContentLink>() { contentLink };
        showcaseItem.SetValue("CaseStudy", screenshots.ToArray());
    }

    // You need to call SaveChanges() in order for the items to be actually persisted to data store showcaseItem.SetValue("Owner", SecurityManager.GetCurrentUserId());
    showcaseItem.SetValue("PublicationDate", DateTime.Now);
    
    // uncomment this line to publish the item instead of saving as draft //mgr.Lifecycle.Publish(showcaseItem); mgr.SaveChanges();
    
    //// TODO: enable workflow //var contextBag = new Dictionary<string, string>(); //contextBag.Add("ContentType", showcaseType.FullName); //WorkflowManager.MessageWorkflow( // showcaseItem.Id, // showcaseType, // null, // "SendForApproval", // false, // contextBag);}

By default, items created will remain in Draft status. To publish an item, simply uncomment the line in the code above the SaveChanges() method.

mgr.Lifecycle.Publish(showcaseItem);

Wrapping Up

With just a few lines of code on a single user control, we were able to quickly extend our module to allow public users to add content items. The Code Reference is full of additional helpful examples to help you customize and make the most of your new dynamic modules.

If you haven't already, take some time to try out the new Module Builder, and as always, be sure to share your experiences with us in the Sitefinity Discussion Forums.

68 comments

Leave a comment
  1. ian Jun 14, 2012
    Hi

    For simplicity, you've excluded validation controls, but if you were to include them how would you do this? Are they normal ASP.NET validation controls or can you link back to your module items to reference the data type etc?

    Thanks        
  2. ian Jun 14, 2012
    Hi

    For simplicity, you've excluded validation controls, but if you were to include them how would you do this? Are they normal ASP.NET validation controls or can you link back to your module items to reference the data type etc?

    Thanks        
  3. Josh Jun 20, 2012
    Because this is a simple user control (ascx) you could certainly use the normal asp.net validation controls (or the Telerik RadInput control) to validate input.

    You can also validate again on the server side with custom logic inside the Submit method. It's entirely up to you!
  4. chris Jan 17, 2018
    This is truly a decent and instructive, containing all data furthermore greatly affects the new innovation. A debt of gratitude is in order for sharing it,  motor club of america presentation
  5. chris Jan 18, 2018
    Yes i am completely concurred with this article and i simply need say this article is extremely pleasant and exceptionally instructive article.I will make a point to be perusing your blog more. You made a decent point however I can't resist the urge to ponder, shouldn't something be said about the other side? !!!!!!THANKS!!!!!!  best digital cameras
  6. Arnold Jan 18, 2018
    Wow! This could be one particular of the most beneficial blogs We’ve ever arrive across on this subject. Actually Wonderful. I’m also an expert in this topic so I can understand your effort. neet 2018 form
  7. chris Jan 20, 2018
    The information you have posted is very useful. The sites you have referred was good. Thanks for sharing... coleus forskohlii 20 forskolin
  8. chris Jan 21, 2018
    Much obliged to you for such an elegantly composed article. It's brimming with astute data and diverting depictions. Your perspective is the best among numerous.  Prevent Cat Spraying
  9. chris Jan 21, 2018
    I got what you mean  , thanks  for posting .Woh I am happy  to find this website through google. Joan
  10. chris Jan 21, 2018
    A debt of gratitude is in order for this article exceptionally accommodating. much appreciated.  guidance sports
  11. ronijames Jan 21, 2018
    Some  truly  nice and useful   info   on this  site,  likewise  I  conceive the  style   holds   excellent  features. bitcoin
  12. chris Jan 23, 2018
    If you don't mind share more like that.  Best Free Forex Signals 2018
  13. ronijames Jan 23, 2018
    I have to show some thanks to the writer just for bailing me out of such a dilemma. As a result of surfing throughout the online world and coming across strategies that were not beneficial, I believed my entire life was well over. Existing minus the solutions to the difficulties you have resolved all through the post is a serious case, and the kind that would have negatively damaged my career if I had not discovered your web page. Your own personal know-how and kindness in playing with every part was tremendous. I’m not sure what I would have done if I hadn’t come upon such a stuff like this. I can also at this moment look ahead to my future. Thanks very much for your specialized and results-oriented help. I won’t be reluctant to suggest your web site to anybody who needs guide on this subject matter. valentine week 2018
  14. Agencia detectives Jan 25, 2018
    i love reading this article so beautiful!!great job!Agencia detectives
  15. chris Jan 26, 2018
    This is an awesome article a debt of gratitude is in order for sharing this useful data. I will visit your web journal consistently for some most recent post. I will visit your web journal routinely for Some most recent post.  طراحی جلد کتاب
  16. chris Jan 30, 2018
    a debt of gratitude is in order for the tips and information..i truly welcome it..  water restoration in delray beach
  17. chris Jan 31, 2018
    The data you have posted is exceptionally helpful. The destinations you have alluded was great. A debt of gratitude is in order for sharing...  free stuff
  18. robert Jan 31, 2018
    This is actually the kind of information I have been trying to find. Thank you for writing this information.precio detective privado Madrid
  19. breast enhancer pills Jan 31, 2018


    Immigration… [...]the time to read or visit the content or sites we have linked to below the[...]… breast enhancer pills

  20. Media Maison Feb 01, 2018
    This is truly a pleasant and instructive, containing all data furthermore greatly affects the new innovation. A debt of gratitude is in order for sharing it  Media Maison
  21. roni Feb 01, 2018
    Rodrick thanks for sharing this! My extensive google search has already been paid using top quality awareness to share with you together with my own relatives. weight loss journey
  22. nesta página Feb 02, 2018
    This is truly a decent and useful, containing all data furthermore greatly affects the new innovation. A debt of gratitude is in order for sharing it  nesta página
  23. jobs in spring tx Feb 02, 2018
    Some really    superb  info  ,  Sword lily I found  this. jobs in spring tx
  24. alquiler de coches en marrakech Feb 02, 2018
    This is truly a decent and educational, containing all data furthermore greatly affects the new innovation. A debt of gratitude is in order for sharing it  alquiler de coches en marrakech
  25. roni Feb 03, 2018
    This kind of lovely blog you’ve, glad I found it!?? dog training pitbull
  26. fort worth Feb 03, 2018
    I’d constantly want to be update on new content on this website, bookmarked! fort worth
  27. roni Feb 03, 2018
    Youre so right.  Im there with you.   Your blog is surely worth a read if anyone comes throughout it.  Im lucky I did because now Ive obtained a whole new view of this.  I didnt realise that this issue was so important and so universal.  You absolutely put it in perspective for me. dog training cesar millan
  28. roni Feb 03, 2018
    I very   happy  to find this website   on bing, just what I was looking  for : D  too  bookmarked . www.putflix.com
  29. roni Feb 04, 2018
    I just wanted to tell you how much my partner and i appreciate anything you’ve discussed to help improve the lives of men and women in this subject matter. Through your current articles, I have gone through just a newcomer to a professional in the area. It’s truly a gratitude to your good work. Thanks Nobel Calling Cards Numerology
  30. online marketing Feb 05, 2018
    When a blind man bears the standard pity those who follow…. Where ignorance is bliss ‘tis folly to be wise…. online marketing
  31. roni Feb 05, 2018
    Hello .finaly I found what I was looking for how did you guys found this information??thank you for your article I found it on Google And I bookmarked it . I’ll share. Please send me updates thank you and have a nice day starting a security company
  32. roni Feb 05, 2018
    Nice post. I learn something tougher on distinct blogs everyday. Most commonly it is stimulating to see content off their writers and use a little there. I’d want to use some with all the content on my blog whether you don’t mind. Natually I’ll offer you a link on the web weblog. Many thanks sharing. finviz
  33. roni Feb 05, 2018
    I dont think Ive scan anything like this before. So good to find somebody with some original thoughts on this subject. thank for starting this up. This website is something that is needed on the web, someone with a little originality. Good job for bringing something new to the internet! internet jetset
  34. voyance Feb 06, 2018
    Hi there, just became alert to your blog through Google, and found that it’s really informative. I am gonna watch out for brussels. I’ll be grateful if you continue this in future. Numerous people will be benefited from your writing. Cheers! voyance
  35. TriboTEX  Feb 06, 2018
  36. cursos de espanhol  Feb 10, 2018
  37. roni Feb 12, 2018
    Good post. I be taught one thing tougher on totally different blogs everyday. It should always be stimulating to learn content material from other writers and practice a bit of something from their store. I’d favor to make use of some with the content on my weblog whether or not you don’t mind. Natually I’ll give you a hyperlink in your net blog. Thanks for sharing. sakong
  38. roni Feb 12, 2018
    You’re the best, beautiful weblog  with great informational content. This is a really interesting and informative content. How To Make 20 Dollars Fast
  39. roni Feb 12, 2018
    We still cannot quite believe that I should often be a kind of checking important points seen on your webblog. Our family and i also are sincerely thankful with regards to your generosity too as for giving me possibility pursue our chosen profession path. Wanted you important information I purchased within your web-site. Flight Case
  40. best vava dash cam 2018 Feb 13, 2018
    This will be the correct blog for really wants to be familiar with this topic. You realize a great deal its practically difficult to argue together with you (not too I just would want…HaHa). You actually put a fresh spin on the topic thats been discussing for some time. Wonderful stuff, just fantastic! best vava dash cam 2018
  41. lucky patcher no root  Feb 14, 2018
    I have been reading out many of your articles and i can claim pretty nice stuff. I will make sure to bookmark your blog. lucky patcher no root
  42. outback vision protocol review Feb 14, 2018
    Outstanding post, you have pointed out some good   details , I  likewise   conceive this s a very good  website. outback vision protocol review
  43. male extra sex pill Feb 14, 2018
    I discovered your blog site site on the search engines and check several of your early posts. Always maintain up the very good operate. I recently additional increase Rss to my MSN News Reader. Looking for toward reading much more on your part later on!… male extra sex pill
  44. interactr review Feb 14, 2018
    Thank you for sharing excellent informations. Your web-site is very cool. I’m impressed by the details that you¡¦ve on this web site. It reveals how nicely you understand  this subject. Bookmarked this web page, will come back for extra articles. You, my friend, ROCK! I found simply the information I already searched all over the place and simply couldn’t come across. What a perfect web-site. rentacarkosova interactr review
  45. Web development company Feb 14, 2018
    Hiya, I am really glad I’ve found this information. Nowadays bloggers publish only about gossips and net and this is actually irritating. A good blog with interesting content, this is what I need. Thanks for keeping this website, I’ll be visiting it. Do you do newsletters? Cant find it. Web development company
  46. Post free business ads uk Feb 14, 2018
    The Exponential Curve of Fascist Unconstitutionality is accelerating straight up and cannot be slowed down  it can only be beheaded, executed albeit politically rather than as Sultans do it. Post free business ads uk
  47. the commission code review 2 Feb 15, 2018
    I gotta  favorite this website   it seems  invaluable   extremely helpful the commission code review 2
  48. web copy cat review Feb 15, 2018
    Bookmarked your fantastic website. Fabulous work, unique way with words! web copy cat review
  49. pari Feb 15, 2018

    your Dad was a great teacher. I always think of Price Lab as my school even though i had to transfer because of my Dads career moves. But because of Price Labs super program of six week programs in various areas of education. Great experience

    http://www.happyholi-2018.org/

  50. motivational Feb 16, 2018
    Cool article it's really. Friend on mine has long been awaiting just for this content. motivational

    Leave a comment