New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.

DotNetNuke Tips and Tricks #20: Module Action Menu Links

Very early in the life of DotNetNuke, modules were fairly limited in their functionality.  Modules could have multiple behaviors attached to them by the framework which were displayed as a list of link buttons.  Very quickly this UI became very cumbersome as we continued to add more and more behaviors to the standard list of behaviors. This UI greatly limited the amount of actions that could be attached to a module and at the time the list of behaviors was fairly static. 

One of the first enhancements that I worked on for my own modules was the ability to create a menu that was attached to the module.   This menu was intended to be customizable by the module developer and the framework and would remove the space limitations that plagued the early framework.  When I showed Shaun the menus he instantly saw the potential and we incorporated them into the framework.

The module action menus were originally designed to be extremely flexible.  I wanted to be able to create links that could perform client-side actions as well as trigger events on the server side, depending on the needs of the module developer.  Many module developers have taken advantage of the server side functionality over the years, but I have not seen many modules which have taken advantage of the client-side functionality.  When I first created the menus, I documented the API using XML Comments, which were not being used anywhere else in the framework.  Until recently the project was not even publishing the API documentation, so these comments went largely unnoticed by the developer community.  I am happy to say that with 5.5 that has changed and the API documentation for the core framework is now available with the rest of the Community Edition download packages.

In this post I’ll walk through a few of the various options for the module action menus.  For my examples I’ll be forgoing the use of the many constructor overloads in favor of using the various properties which I think make the code more readable.

As most module developers are aware, the first step in using the Module Action Menus is to have your module implement the IActionable interface.  This interface defines a single property which returns a collection of ModuleActions.

Namespace DotNetNuke.Modules.MenuExample

  Partial Class View
    Inherits Entities.Modules.PortalModuleBase
    Implements DotNetNuke.Entities.Modules.IActionable

    Public ReadOnly Property ModuleActions As ModuleActionCollection 
			Implements ModuleActions

        Dim modActions As New ModuleActionCollection()
        Return modActions
      End Get
    End Property
  End Class

End Namespace

Inside of this property we’ll add whichever actions are appropriate for the module.  Using the module action menus, it is possible to define a JavaScript method which is called when the associated menu item is selected.  I usually use this in my own modules when I want to popup a form for the user that I have created using jQuery or some other client-side script.  This minimizes postbacks and makes for a much more responsive UI.

' JavaScript Example
Dim jsAction As New ModuleAction(ModuleContext.GetNextActionID())
With jsAction
  .Title = "JavaScript Example"
  .CommandName = ModuleActionType.AddContent
  .ClientScript = "alert('Isn\'t this cool!')"
  .Secure = Security.SecurityAccessLevel.Edit
End With

There are times when you will want to redirect the user to some specific URL within the current site or even on another site.  You might want to provide access to the latest documentation or link the user to the relevant support forum on your website.  This behavior is controlled by the URL property.

' URL Example
Dim urlAction As New ModuleAction(ModuleContext.GetNextActionID())
With urlAction
  .Title = "Url Example"
  .CommandName = "redirect"
  .Url = ""
  .Secure = Security.SecurityAccessLevel.Edit
End With

While linking to a URL is good, you will probably want to open the URL in a new window so that the user doesn’t lose their place on the website where they were using your module.  To do this, just set the NewWindow property to true.

' New Window Example
Dim newAction As New ModuleAction(ModuleContext.GetNextActionID())
With newAction
  .Title = "New Window Example"
  .CommandName = "newwindow"
  .Url = ""
  .NewWindow = True
  .Secure = Security.SecurityAccessLevel.Edit
End With

Occasionally, you will want to do some additional processing on the server-side before taking further action.  Setting the UseActionEvent will override the behavior of the URL setting and force a server side event to be triggered.

' URL Postback Example
Dim urlEventAction As New ModuleAction(ModuleContext.GetNextActionID())
With urlEventAction
  urlEventAction.Title = "Action Event Example"
  urlEventAction.CommandName = "redirect"
  urlEventAction.CommandArgument = "cancel"
  urlEventAction.Url = ""
  urlEventAction.UseActionEvent = True
  urlEventAction.Secure = Security.SecurityAccessLevel.Edit
End With

In order to respond to the event you will need to register an event handler in the Init event of your module control.

Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init

  'Add an Action Event Handler to the Skin
  AddActionHandler(AddressOf MyActions_Click)
End Sub

Once you have registered the ActionHandler you are free to process the action using whatever business rules are appropriate for your specific module.

Private Sub MyActions_Click(ByVal sender As Object, ByVal e As Entities.Modules.Actions.ActionEventArgs)
  Skins.Skin.AddModuleMessage(Me, _
	  String.Format(Localization.GetString("ClickMessage", LocalResourceFile), e.Action.CommandName), _

Select Case e.Action.CommandName.ToLowerInvariant
  Case "redirect"
    If e.Action.CommandArgument.ToLowerInvariant <> "cancel" Then
      Skins.Skin.AddModuleMessage(Me, _
        "Canceled the Redirect", _
        End If
  End Select
End Sub

This post highlights just a few of the hidden capabilities of the Module Action Menu.  I urge you to take a few minutes in the documentation exploring some of the features.  I also recommend that you examine some of the many examples of how others are using Module Action Menus.  The HTML/Text module is a great place to start.



I have done this in my DNN 6 installation and it worked great. Now that I upgraded to DNN 7, it doesn't work anymore. What changed? Is there a way I can make it work?

Thank you!
Mona Thursday, February 20, 2014 8:10 AM (link)
Michael Tobisch
Thanks Joe for this great post - the problem I have is: How can I add a piece of Javascript to the Url Postback example to confirm (or cancel) the action, e.g. when I want to delete a bunch of records? See also

(Just adding something to the ClientScript property does not work - the script is not executed. Also the JavaScript example does not work.)

Happy DNNing!
Michael Tobisch Sunday, March 3, 2019 9:54 AM (link)
Michael Tobisch
Another question: How can I achieve a full postback from a module action menu item (e.g. for CSV export ...)

Happy DNNing!
Michael Tobisch Saturday, March 16, 2019 1:34 AM (link)
Andrew Hoefling

I ran into the exact same problem with ClientScript not working as I expected or this blog documented. My guess is DNN has since changed how it handles JavaScript being executed from the Module Action Menu.

To get it working use the URL property like so:

Url = " hello world')"

where " hello world')" is the javascript you want to invoke.

I wrote a quick blog documenting this -

Hope this helps!
Andrew Hoefling Tuesday, September 10, 2019 7:54 AM (link)

Comment Form

Only registered users may post comments.


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Davies (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out