+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

How to display related data in dynamic content widgets

by Stoimen Stoimenov
(With Sitefinity version 5.1 and above there is a simple way to relate dynamic modules and here is a blog post that summarizes the process)

Dynamic modules built with the Module Builder give you the ability to relate items using Guid fields. But after relationships between content types are defined, it is nice to have the items displayed and in the front end. With the 5.1 release we have done some modifications to the dynamic content widgets which provide you with that ability. 

To configure the dynamic content widgets first we need to have some content types and data. For instance you could have "Artist" and "Albums" types related in a way that the "Artist" type has a field “Albums” that is an array of GUIDs field and it is populated with the IDs of the related albums.

Here is sample code of what I am trying to describe. First we create our data:

 

public void CreateData()
        {
            List<Dictionary<Guid, string>> albumCollection = new List<Dictionary<Guid, string>>()
            {
                new Dictionary<Guid, string>()
                    {
                        {Guid.NewGuid(), "album 1 for artist 1"},
                        {Guid.NewGuid(), "album 2 for artist 1"},
                        {Guid.NewGuid(), "album 3 for artist 1"}
                    },
                new Dictionary<Guid, string>()
                    {
                        {Guid.NewGuid(), "album 1 for artist 2"},
                        {Guid.NewGuid(), "album 2 for artist 2"},
                        {Guid.NewGuid(), "album 3 for artist 2"}
                    }
            };
 
            foreach (var collection in albumCollection)
            {
                foreach (KeyValuePair<Guid, string> kvp in collection)
                {
                    CreateAndPublishAlbum(kvp.Key, kvp.Value);
                }
            }
 
            CreateAndPublishArtist("artist 1", "Rock", albumCollection[0].Keys.ToArray());
            CreateAndPublishArtist("artist 2", "Pop", albumCollection[1].Keys.ToArray());
        }
 
        public void CreateAndPublishAlbum(Guid itemId, string title)
        {
            DynamicModuleManager dynamicModuleManager = DynamicModuleManager.GetManager();
            Type albumsType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.RelatedDataTest.Albums");
            DynamicContent albumsItem = dynamicModuleManager.CreateDataItem(albumsType, itemId, dynamicModuleManager.Provider.ApplicationName);
 
            // This is how values for the properties are set
            albumsItem.SetValue("Title", title);
            albumsItem.SetValue("Owner", SecurityManager.GetCurrentUserId());
            albumsItem.SetValue("PublicationDate", DateTime.Now);
            albumsItem.SetValue("UrlName", new Lstring(Regex.Replace(title, UrlNameCharsToReplace, UrlNameReplaceString)));
 
            // We can now call the following to publish the item
            ILifecycleDataItem publishedAlbumsItem = dynamicModuleManager.Lifecycle.Publish(albumsItem);
 
            //You need to set appropriate workflow status
            albumsItem.SetWorkflowStatus(dynamicModuleManager.Provider.ApplicationName, "Published");
 
            // You need to call SaveChanges() in order for the items to be actually persisted to data store
            dynamicModuleManager.SaveChanges();
        }
 
        //Publish a new artists item
        public void CreateAndPublishArtist(string title, string musicStyle, Guid[] albums)
        {
            DynamicModuleManager dynamicModuleManager = DynamicModuleManager.GetManager();
            Type artistsType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.RelatedDataTest.Artists");
            DynamicContent artistsItem = dynamicModuleManager.CreateDataItem(artistsType);
 
            // This is how values for the properties are set
            artistsItem.SetValue("Name", title);
            artistsItem.SetValue("Owner", SecurityManager.GetCurrentUserId());
            artistsItem.SetValue("Albums", albums);
            artistsItem.SetValue("MusicStyle", musicStyle);
            artistsItem.SetValue("UrlName", new Lstring(Regex.Replace(title, UrlNameCharsToReplace, UrlNameReplaceString)));
 
            // We can now call the following to publish the item
            ILifecycleDataItem publishedArtistsItem = dynamicModuleManager.Lifecycle.Publish(artistsItem);
 
            //You need to set appropriate workflow status
            artistsItem.SetWorkflowStatus(dynamicModuleManager.Provider.ApplicationName, "Published");
 
            // You need to call SaveChanges() in order for the items to be actually persisted to data store
            dynamicModuleManager.SaveChanges();
        }
 
        private const string UrlNameCharsToReplace = @"[^\w\-\!\$\'\(\)\=\@\d_]+";
        private const string UrlNameReplaceString = "-";

As you can see two artists and six albums are created. Albums IDs are passed to the artists “Albums” fields so that the relations are set. Every artists has three albums. The next step will be to configure the widgets that are created with the custom content types. For this purpose we have added two new properties in the widgets. Place both content types widgets in a single page and in the albums widget advanced settings set RelatedDataTypeName to the content type name of the artist type (Telerik.Sitefinity.DynamicTypes.Model.RelatedDataTest.Artists). Set RelatedDataFieldName property in the same widget to the name the field of the related type where the id’s of the items are stored – in this case “Albums” field of the artist content type. Save and publish. When the page is viewed in the front end and an artist is selected the corresponding albums will be displayed. 

With the latest version of Sitefinity Thunder comes a very nice option to create items selector for your related data in the backend which will ease the process. Have a look at the documentation article about configuring the new selector control. 

Here you can find a video that goes through all of the configuration steps.

 

6 comments

Leave a comment
  1. Garrett Oct 15, 2012
    Excellent Article!

    However, is it possible to do this the other way around?

    I have a custom module called "Video Games" with a custom "News" type and "VideoGame" type. I want to be able o select the "VideoGames" in the Array of GUID's when adding a news article, but only want to display the news articles that are associated with that game.

    Thanks,

    Garrett
  2. Georgi Dimitrov Nov 09, 2012
    Hi Garrett,

    Sorry for the late response.

    About your case I can suggest you the following solution:
    1. Use Thunder to create selector for dynamic items following this article: http://www.sitefinity.com/documentation/documentationarticles/creating-field-control-with-selector-for-dynamic-items
    2. Once you have created news items and associated video games to them you will need a little custom development in order to display the game with the related news.
      1. Create a custom control that inherits DynamicContentView. Please find below sample code:
        using System;
        using System.Linq;
        using Telerik.Sitefinity.DynamicModules;
        using Telerik.Sitefinity.DynamicModules.Model;
        using Telerik.Sitefinity.DynamicModules.Web.UI.Frontend;
        using Telerik.Sitefinity.GenericContent.Model;
        using Telerik.Sitefinity.Model;
        using Telerik.Sitefinity.Utilities.TypeConverters;
         
        namespace SitefinityWebApp
        {
            public class CustomDynamicContentView : DynamicContentView
            {
                protected override void InitializeDetailView(DynamicContent dataItem)
                {
                    base.InitializeDetailView(dataItem);
         
                    if (dataItem != null)
                    {
                        var dynamicModuleManager = DynamicModuleManager.GetManager();
                        var newsType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.VideoGames.News");
                        //gets all news item with status Live and VideoGames field containing the current video game
                        var newsItem = dynamicModuleManager.GetDataItems(newsType).Where(d => d.Status == ContentLifecycleStatus.Live && d.GetValue<Guid[]>("VideoGames").Contains(dataItem.OriginalContentId));
                        //sets the news items as source for the master view control and initialize it
                        this.MasterViewControl.DataSource = newsItem;
                        this.InitializeMasterView();
                    }
                }
            }
        }
      2. You can add your control to the toolboxes config and drop it on any page.
        1. Open ToolboxesConfig.config located in App_Data\Sitefinity\Configuration folder.
        2. Duplicate the toolbox item for Video games type, it should looks like that:<add enabled="True" type="Telerik.Sitefinity.DynamicModules.Web.UI.Frontend.DynamicContentView, Telerik.Sitefinity" title="VideoGames" cssClass="sfNewsViewIcn" moduleName="Video Games" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.VideoGames.Videogame" DefaultMasterTemplateKey="a0203c11-552a-4303-8405-07ca0c854b96" DefaultDetailTemplateKey="4e89f1ea-0926-4322-9db9-be27b2d30e11" visibilityMode="None" name="Telerik.Sitefinity.DynamicTypes.Model.VideoGames.Videogame" />
        3. Change the type attribute of the newly created toolbox item to point to your custom control, for example: type="SitefinityWebApp.CustomDynamicContentView, SitefinityWebApp"
        4. Change the title attribute to some meaningful, for example: title="VideoGames with News"
        5. Restart your application

    Following these steps you should be able to drop your custom widget on any page and when you navigate to any Video game it will display the news items related to it.

    I hope this information would be helpful for you. Please do not hesitate to contact me again if you need any further information.    

    All the best,
    Georgi Dimitrov
  3. Garrett Nov 10, 2012
    Hi Georgi,

    Thanks for the information, however the result winds up being a bit strange.

    I wanted to be able to Master/Detail the news (Video Games would live in its own widget and News would live in its own) like the original blog post does.

    Your example "ties in" a list of news items into the VideoGames widget, which means once the News Items are shown, you can't interact with them at all since any link to details would try to direct me to a generated Video Games page which is incorrect behavior (not to mention I had to add the columns of the News type to the VideoGame type just to get this to work).

    Is it possible for this example to be made to better mimic the behavior of the blog post?

    Thanks,

    Garrett
  4. Georgi Dimitrov Nov 13, 2012
    Hi Garrett,

    Sorry if I haven’t understood you correctly.

    In order to keep the Video games and the News in separate widgets you will need to modify your code. Please find updated steps bellow:

    1. Create a custom control that inherits DynamicContentView using the following sample code:
      using System;
      using System.Linq;
      using System.Web.UI;
      using Telerik.Sitefinity.DynamicModules;
      using Telerik.Sitefinity.DynamicModules.Model;
      using Telerik.Sitefinity.DynamicModules.Web.UI.Frontend;
      using Telerik.Sitefinity.GenericContent.Model;
      using Telerik.Sitefinity.Model;
      using Telerik.Sitefinity.Utilities.TypeConverters;
       
      namespace SitefinityWebApp
      {
          public class CustomDynamicContentView : DynamicContentView
          {
              protected override void InitializeMasterView()
              {
                  var videoGame = this.GetVideoGameFromUrl();
                  if (videoGame != null)
                  {
                      var dynamicModuleManager = DynamicModuleManager.GetManager();
                      var newsType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.VideoGames.News");
                      //gets all news item with status Live and VideoGames field containing the current video game
                      var newsItem = dynamicModuleManager.GetDataItems(newsType).Where(d => d.Status == ContentLifecycleStatus.Live && d.GetValue<Guid[]>("VideoGames").Contains(videoGame.OriginalContentId));
                      //sets the news items as source for the master view control and initialize it
                      this.MasterViewControl.DataSource = newsItem;
       
                      base.InitializeMasterView();
                  }
              }
       
              private DynamicContent GetVideoGameFromUrl()
              {
                  DynamicContent videoGame = null;
                  var urlParams = this.GetUrlParameterString(true);
       
                  if (!urlParams.IsNullOrEmpty())
                  {
                      string redirectUrl = string.Empty;
                      var isPublished = !this.IsDesignMode();
                      var videoGameType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.VideoGames.Videogame");
       
                      videoGame = this.DynamicManager.Provider.GetItemFromUrl(videoGameType, urlParams, isPublished, out redirectUrl) as DynamicContent;
                  }
       
                  return videoGame;
              }
          }
      }
    2. Add your control to the toolboxes config and drop it on any page.
    1. Open ToolboxesConfig.config located in App_Data\Sitefinity\Configuration folder.
    2. Duplicate the toolbox item for News type, it should looks like that: <add enabled="True" type="Telerik.Sitefinity.DynamicModules.Web.UI.Frontend.DynamicContentView, Telerik.Sitefinity" title="News" cssClass="sfNewsViewIcn" moduleName="Video Games" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.VideoGames.News" DefaultMasterTemplateKey="54f5eaea-6dd2-43ee-9797-300971786177" DefaultDetailTemplateKey="c974a894-cb34-460c-95b3-6d3089fb4981" visibilityMode="None" name="Telerik.Sitefinity.DynamicTypes.Model.VideoGames.News" />
    3. Change the type attribute of the newly created toolbox item to point to your custom control, for example: type="SitefinityWebApp.CustomDynamicContentView, SitefinityWebApp"
    4. Change the title attribute to some meaningful, for example: title="News related to video game"
    5. Restart your application
    Now the newly created widget will display only news items related to current video game. The current video game will be resolved from the URL.

    Please let me know if you have any additional questions.

    Best regards,
    Georgi Dimitrov


  5. Hilary Addison Aug 12, 2016
    Sitefinity Improves your substance and correspondence with wonderful pictures and drawing in recordings. I am an excellent video artist at HelloAnimations & I have a plan to make my video blog by using Sitefinity CMS. Spare time and cash by dealing with your computerized resources from a focal area, and offer them crosswise over pages and destinations. Effortlessly compose your documents with progressive libraries, classifications and labels.
  6. William Jack Sep 19, 2016
    Great

    Leave a comment