Learn More





DNN Community Blog

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.

Module Development in DNN 8: 5 - New tokens to support building pure SPA modules

DNN 8 will support creating modules using a SPA (Single Page Application) model using HTML 5, JavaScript and ASP.NET Web API based web services.  In a previous blog in this series I showed how you can set up your environment to create SPA modules. This model development style has been available ever since we added support for ASP.NET Web API, but in DNN 8 we have added support for html files to be module controls.  This means that we no longer require some form of code-behind file.  So how do we do things like registering JavaScript files that we used to do in those code behind files.  In this blog I describe how we have extended DNNs token support to provide these abilities.  As before the source code for my examples is available on Github at

Registering JavaScript and Css files

We already have examples in DNN of using HTML, JavaScript (AJAX) and ASP.NET Web API for developing modules.  So in this blog I will focus on the new tokens that can be used to accomplish most of the tasks that used to be done in the code behind files.  In our existing examples (the Member Directory and Messaging modules used in the DNN User Profile) we register JavaScript and css files by using a server-side control (DnnJsInclude or DNNCssInclude) or by making a call to the Client Resource Framework.  Neither of these approaches is possible with a purely HTML control.

In order to register JavaScript and css file we have added two new tokens.  These tokens are slightly different from the existing Tokens.  Traditional DNN  Tokens have the format [Entity : Property] and return a string, i.e. the token is replaced by the value of the property.

These new Tokens do not return anything – instead some action take place – in this case the JavaScript or CSS files are registered with the Client Resource Framework.  Another feature of these tokens is that the syntax is a little different as the right hand side (the “property”) is expressed as JSON.  This allows us to define a standard approach for all of these extended tokens.

Listing 1: Use of the JavaScript token

[JavaScript:{ jsname: "Knockout" }]
[JavaScript:{ path: "~/DesktopModules/Dnn/ContactList/ClientScripts/contacts.js"}]
[JavaScript:{ path: "~/DesktopModules/Dnn/ContactList/ClientScripts/util.js"}]
[JavaScript:{ path: "~/Resources/Shared/scripts/dnn.jquery.js"}]

Listing 1 shows the use of the JavaScript token in the example code.  If a JavaScript Library has been defined (such as jQuery or Knockout) you can use the first form.  The first form supports  the following parameters:

  • jsname – the name of the default library
  • version – the version to use
  • specific – a setting which controls how the framework chooses the version to render – this has 4 values
    • Exact – the exact version
    • LatestMajor – the latest major version
    • LatestMinor – the latest minor version
    • Latest – the latest version registered.

The second form is used for JavaScript files that have not been registered as JavaScript libraries.  This form supports the following parameters:

  • path – the path to the location of the file
  • priority – the priority to use when rendering the link – files with lower priority are rendered first
  • provider – the provider to use

Note: that the token name “js” can also be used as an alias to the JavaScript token.

The example code on Github does not include an example of the Css token as the example code only includes the standard DNN module.css file but the parameters for the Css token are exactly the same as the second form of the JavaScript token. Listing 2 shows the statements used in the new Dynamic Content Type Manager which will be included in CTP 3 of DNN 8, which registers a css file for codemirror as well as the Font-Awesome icon library.  Note that remote paths, such as a CDN can be used.

Listing 2: Use of the Css token

[Css:{ path: "//"}]
[Css:{ path: "~/Resources/Shared/components/CodeEditor/lib/codemirror.css"}]

An additional feature of these tokens is that they can also be used in the DNN HTML module to register JavaScript or Css.

Resx Localization Token

We have also added a token to allow Localization values to be rendered into the HTML.  This is more like a traditional Token Replace token in that this token when parsed is replaced by a value – the result of the localization.

Listing 3: Use of the Resx Localization token

   1:  <div class="contactCard">
   2:      <div class="right">
   3:          <a title="[Resx:{key:'Edit'}]" data-bind="click: $parent.editContact">
   4:              <i class="fa fa-pencil"></i>
   5:          </a>
   6:          <a title="[Resx:{key:'Delete'}]" data-bind="click: deleteContact">
   7:              <i class="fa fa-trash"></i>
   8:          </a>
   9:      </div>
  10:      <div>
  11:          <span data-bind="text: firstName"></span>
  12:          <span data-bind="text: lastName"></span>
  13:      </div>
  14:      <div>
  15:          <span>[Resx:{key:"Email"}]</span>
  16:          <span data-bind="text: email"></span>
  17:      </div>
  18:      <div>
  19:          <span>[Resx:{key:"Phone"}]</span>
  20:          <span data-bind="text: phone"></span>
  21:      </div>
  22:      <div>
  23:          <span>[Resx:{key:"Twitter"}]</span>
  24:          <span data-bind="text: twitter"></span>
  25:      </div>
  26:  </div>

This token also uses the JSON format.  It supports two parameters:

  • key – the resource key
  • localresourcefile – the local resource file

If the localresourcefile parameter is not included then the file defaults to <<HTMLFileRoot >>.resx where HTMLFileRoot is the filename (without extension) of the current HTML file.  i.e. if the html file is ContactList.html the relevant resx file is ContactList.resx.

Note that because the html is parsed on the server before being rendered to the browser the token can be used inside an attribute, and the “localized value” is found in the HTML sent to the browser.

ModuleContext Token

In DNN8 CTP 2 there is an additional token (which is still under development) – the ModuleContext token.  This token is designed to provide some support for passing some module context to the client.  In reality the only ModuleContext that is required is the module Id, as a JavaScript developer could write a Web API service that uses the moduleId to get more detailed context.  But this requires an extra request, so we are still considering what we need to provide as a minimal set of properties for this token.

CTP 2 supports two properties for the ModuleContext token:

  • moduleId – the Id of the module
  • issuperuser – a Boolean that indicates whether the current user is a Super (Host) User

That's it for new tokens.  Have fun developing new SP modules – let us know what you think.

For more information


Stefan Cullmann
Hi Charles,
the tokens are great, but they might be not enough. I am working in a project with angular and multiple routes/ templates. In that case the views (small html files) are loaded directly from angular. I think in that case it is impossible to work with tokens.

I am using an other trick in my angular and knockout modules. I am creating a simple JS object, which acts as a dictionary for localization. Thanks to a tip from Torsten it is now very easy to use in "classic" SPA DNN Modules.
Please have a look at this gist to catch the idea:
Maybe something similar can be done for the new SPA modules?

Best, Stefan

Stefan Cullmann Wednesday, July 08, 2015 2:55 PM (link)
Charles Nurse
@Stefan it is on the roadmap to be able to load a localized dictionary by calling a web service. We already use that kind of idea in Evoq.
Charles Nurse Wednesday, July 08, 2015 4:25 PM (link)
kurt wilby
Hi Charles,

I have four Questions:
1. How secure are tokens. I read Daniel Mettler´s comments on tokens on and I found it confusing.
2. Html files are module control in 8.0.0. Does this mean that I cannot directly access them using URL´s. What does it mean to have html files as module controls. What are the advantages.
3. I am using AngularJS with UI-router and would like to know how to use multiple Html files as module controls.

Also, Bruce Chapman wrote that he will give a ´SPA Razor, WebAPI and AngularJS example´ of his SPA To-Do list Module. Any idea when we will see his creation.

kurt wilby Thursday, July 09, 2015 8:15 PM (link)
Charles Nurse
@kurt (1) tokens are as secure as the module control. The Javasript and Css tokens which are exposed for use in the HTML module are therefore as secure as the module's Edit permissions.

(2) you can directly access these files using the url - e.g. DesktopModules/MyModule/MyModule.html will render the html BUT in this case the tokens will not be parsed.

(3) I cannot answer that as I don't have much personal experience with Angular. However as I mention in the next blog - A SPA module, if it truly is a Single Page Applciation should only have one module control (froma DNN perspective). if your JavaScript framework can manage other HTML files then let it.
Charles Nurse Monday, July 13, 2015 6:19 PM (link)

Comment Form

Only registered users may post comments.


2sic Daniel Mettler (124)
Aderson Oliveira (15)
Alec Whittington (11)
Alex Shirley (10)
Andrew Nurse (30)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (21)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (203)
Chris Paterra (55)
Clinton Patterson (28)
Cuong Dang (21)
Daniel Bartholomew (2)
Dave Buckner (2)
David Poindexter (3)
David Rodriguez (2)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (74)
Geoff Barlow (6)
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 (269)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matthias Schlomann (15)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Mike Horton (19)
Mitchel Sellers (28)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Peter Donker (52)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott S (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)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (2)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (37)
Will Strohl (163)
William Severance (5)
Try Evoq
For Free
Start Free Trial
a Demo
See Evoq Live
Need More Information?