DotNetNuke Tips and Tricks #13: Re-using Content with jQuery

Aug 13

Written by: Joe Brinkman
8/13/2009 3:00 AM  RssIcon

Over the past 6 years I have watched as DotNetNuke matured into a well-rounded platform that is capable of meeting the needs of a wide variety of individuals and organizations.  One of the keys to the platform’s success is that it continues to leverage technology to make it easy to build sites the way you want. 

A user recently asked me how they could re-use the content from one page on another page in their site.  A couple of years ago I would have suggested that they make a “copy” of the module using the built-in capabilities.  This works well when you are trying to duplicate the entire content of the module, however, there are times when you just want a portion of the content.  In the past the answer would have been to split up the content on the original page – which might require changing your skin and may not be possible when using 3rd party modules.

The optimal solution would not require me to make any changes to the original page, but would instead allow me just to grab specific content and display it on a new page.  Thanks goodness we added jQuery support in 4.9 and 5.0.  This problem is really easy to solve with some simple html and a jQuery one-liner.

For a simple scenario, lets assume I want to copy the quicklinks from default template on my site’s homepage (I’m using the standard DotNetNuke install so you can follow along).  The quicklinks are a subset of the content from an HTML module on the home page.

Add a test page to your site so that we can see how this works.  The test page should come pre-installed with an HTML module.  If your copy does not, go ahead and add one now… don’t worry, I’ll wait for you to finish.

Now we edit the content in our HTML module and place a simple div in our content.

This content will be replaced.

I use a simple trick that Kevin Schreiner showed me a couple years ago to inject a script into my page without worrying about the HTML module stripping it out.  Open the module settings and expand the “Advanced Settings” node to display the module Header and Footer items.  We’ll place our JavaScript into the Header which is not altered when it is injected into the page.

The following JavaScript will run after the page has finished loading.

The $("#placeholderId") line gets a reference to the element we defined in our HTML.  The .load method, makes an AJAX call to retrieve the home page, and then finds the content that matches the #QuickLinks selector.

All of this works really well, but this is DotNetNuke and we can make this much easier.  So lets create a simple module that handles all this drudgery for us.  I’m going to call this module ContentGrabber.

The ContentGrabber module has a simple view page that will inject our placeholder and JavaScript.  We also add a settings page because it wouldn’t be very interesting if we could only grab the quicklinks from the home page.

My view page has very little markup.  One change I did make to our original script and HTML was to add a few code expressions to allow us to specify different pages and jQuery selectors.  We also made sure to generate a unique content ID so that we could add multiple modules to the same page.

<%@ Control language="vb" 
    Inherits="DotNetNuke.Modules.ContentGrabber.ViewContent" 
    CodeFile="ViewContent.ascx.vb" 
    AutoEventWireup="false" Explicit="True" %>

<% If Not String.IsNullOrEmpty(PageURL) Then%>



<% End If%>

Update the module settings to replace this content.

Now the only thing left to do is add some code to the code-behind to retrieve the PageURL and Query values from our module settings.  Notice that there are really only two lines of actual code, beyond the boilerplate namespace, class and property declarations.

Imports System

Namespace DotNetNuke.Modules.ContentGrabber

    Partial Class ViewContent
        Inherits Entities.Modules.PortalModuleBase

        Public ReadOnly Property PageURL() As String
            Get
                Return CType(Me.Settings(GRABBER_URL), String)
            End Get
        End Property

        Public ReadOnly Property Query() As String
            Get
                Return CType(Me.Settings(GRABBER_QUERY), String)
            End Get
        End Property

    End Class

End Namespace

So now that our view page is complete, lets create a page to handle editing our settings. 

<%@ Control language="vb" 
    Inherits="DotNetNuke.Modules.ContentGrabber.Settings" 
    CodeFile="Settings.ascx.vb" 
    AutoEventWireup="false" 
    Explicit="True" %>
<%@ Register TagPrefix="dnn" 
    TagName="Label" 
    Src="~/controls/LabelControl.ascx" %>

There is not much interesting going on here.  Yes, yes.  I know.  I used a table.  It’s ok.  The W3C hasn’t completely deprecated that tag yet.  If you would prefer to be semantically correct then feel free to use divs and CSS.  We’ll wait the extra 10 minutes for you to catch up.

ContentGrabberSettings

OK.  Hopefully I didn’t lose any readers over that whole table thing.  Let’s move on the code-behind.

Imports System
Imports System.Web.UI

Namespace DotNetNuke.Modules.ContentGrabber

    Partial Class Settings
        Inherits DotNetNuke.Entities.Modules.ModuleSettingsBase

        Public Overrides Sub LoadSettings()
            Try
                If Not Page.IsPostBack Then
                    txtPage.Text = CType(ModuleSettings(GRABBER_URL), String)
                    txtQuery.Text = CType(ModuleSettings(GRABBER_QUERY), String)
                End If
            Catch exc As Exception    'Module failed to load
                ProcessModuleLoadException(Me, exc)
            End Try
        End Sub

        Public Overrides Sub UpdateSettings()
            Try

                ' update modulesettings
                Dim objModules As New DotNetNuke.Entities.Modules.ModuleController
                objModules.UpdateModuleSetting(ModuleId, GRABBER_URL, txtPage.Text)
                objModules.UpdateModuleSetting(ModuleId, GRABBER_QUERY, txtQuery.Text)

            Catch exc As Exception    'Module failed to load
                ProcessModuleLoadException(Me, exc)
            End Try
        End Sub

    End Class

End Namespace

This code was a little more involved, but still pretty simple.  I’ll leave it up to the user to create the associated resource file for our labels.  At this point we have a fully working module that packages up our original script in a nice little module with settings to handle the customizable behavior.  As you can see in the image below, both approaches provide the same results.

ContentGrabber 

I have left a few exercises for the reader.

  1. Substitute the URL control for the URL setting.
  2. Add an AJAX waiting image while loading the HTML.
  3. Allow the user visually select the page element(s) they want to copy.

Download the working module from CodePlex.

6 comment(s) so far...


Gravatar

re: DotNetNuke Tips and Tricks #13: Re-using Content with jQuery

Excellent use. I will have to remember this in the future. I guess the main thing to be concerned about is when the content will be rendered and how process intensive it will be for each page view, since it's basically rendering two pages to show one.

By Jonathan Sheely on   8/13/2009 8:29 AM
Gravatar

re: DotNetNuke Tips and Tricks #13: Re-using Content with jQuery

@Jonathan - Yes there is a performance hit, but like everything in software, it is up to the individual to determine whether the tradeoff is worth the reward.

By Joe Brinkman on   8/13/2009 9:30 AM
Gravatar

re: DotNetNuke Tips and Tricks #13: Re-using Content with jQuery

Excellent! I think, though, that you failed to point out what could be a very popular use case: cross-portal display of content (non-RSS content). The provided example draws from the same portal but can just as easily draw from a different portal, installation or (gasp) non-DNN website. I predict that this post will make a lot of DNN admins very happy. Loved the 'table' comments as well...

By mamlin on   8/13/2009 5:36 PM
Gravatar

re: DotNetNuke Tips and Tricks #13: Re-using Content with jQuery

Thank you very much. Your tips are very useful to us.

By Duc Minh Nguyen on   8/13/2009 6:03 PM
Gravatar

re: DotNetNuke Tips and Tricks #13: Re-using Content with jQuery

Joe, You forgot to mention that this really messes up your statistics and performance. Jquery's .load downloads the full page to the user's browser and extracts the needed information from it. That's a full page hit. If a user browses 5 pages it looks like he hit 10 pages.

By Casper on   8/13/2009 11:59 PM
Gravatar

re: DotNetNuke Tips and Tricks #13: Re-using Content with jQuery

@mamlin - Yeah I was trying to avoid the discussion of screen scraping other sites due to copyright issues. @Casper - Yes, as I mentioned, there are tradeoffs to this approach. It is no different than using an IFrame which suffers from the same limitation. You can minimize the impact by using the "print" view URL for a specific module on the page. This URL is non-trivial and is likely to cause some confusion for inexperienced users. http://localhost/dnn511pe/Home/tabid/39/mid/353/dnnprintmode/true/Default.aspx?SkinSrc=[G]Skins%2f_default%2fNo+Skin&ContainerSrc=[G]Containers%2f_default%2fNo+Container It might be worthwhile to make this an option for the user on the settings page such that they could just identify a tab and module to use, and the Content Grabber could automatically use the printmode URL.

By Joe Brinkman on   8/14/2009 12:29 AM
dummy