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.

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 8, 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 8, 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 9, 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)
Michael Durthaler

I'm not quite finding a bridge between what I use already for MVC and how to port that over to DNN MVC. At work, we're not using Razor, we just use HTML forms jQuery and Bootstrap for our simpler projects, Ext JS for our more complex projects.

I have separate JavaScript files as required, separate CSS files to implement BootStrap's method of displaying data in table format without using tables, i.e. you have a div with class = row and contained in it as many columns are needed with their classes being something like class = col1-md , col2md, etc. I'm just fudging the class names.

We're using controllers to return data in Json format and parsing in js. All obvious stuff.

I want to do the same thing in DNN and not have to manually write script tags, have that separate ~/resources/css and ~/resources/js folder for my extensions to jQuery.

DNN MVC seems to be centralized around Razor. I'm sure there are examples out there for doing things as I'm accustomed but if not ... I can accept having to learn Razor now. It looks like fun but I want to get the ball rolling much faster. That's best accomplished by implementing what I'm used to.

Thanks for any input.
Michael Durthaler Saturday, June 3, 2017 4:22 PM (link)

Comment Form

Only registered users may post comments.


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (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)
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