Tutorial 2: Templates & Rendering

All content in the Dynamicweb core is rendered by the rendering engine using templates - which are basically text based files containing markup.

Dynamicweb supports both HTML templates, Razor templates, and Razor templates with ViewModels – we will use Razor templates in all template examples, since pure html templates are outdated and Razor with ViewModels is a new and fairly experimental feature.

A template contains markup for the section it is responsible for. By using dynamic tags, into which data from the model is merged, a final output to the frontend is produced. If you enter the following markup in a template 

<p>Welcome to the @GetString("DwPageName")</p>

The frontend will output the following, when a page called ‘Store’ is visited: 

Welcome to the Store

In this tutorial you will be introduced to:

  • The template hierarchy in Dynamicweb
  • The rendering process
  • The tools available for frontend development

For any given view accessible to the website visitor, there is a hierarchy of templates, each with its own area of responsibility as illustrated below in Figure 2.1.

Figure 2.1 The template hierarchy
  • The Master template contains markup that is common for a lot of pages. This could be the entire <head> section, references to css and javascript libraries and in many cases also for menus and mini cart, if they are shared across the website.
  • The Page template contains the main markup, sections and columns of a particular page type – e.g. blog, shop or frontpage.
  • The Paragraph template controls how the content (text, image, or app output) of a single paragraph is organized.
  • The App template controls the appearance of app output, e.g. a product list, a login form, etc.. 

The rendering process starts by the user requesting a page, which is rendered by a Page template. The Page and Master templates are merged into one and cached to disc in order to ensure the best performance, so if any change have been made to either of these files, this merging will occur. This step is skipped on recurring requests until a new file is saved or the merging is forced.

A Page template can contain any number of content placeholders, which are places where you can insert paragraph content. Regular paragraphs can contain text and images, whereas item-based paragraphs can contain all sorts of content. Both paragraph types may have an app attached – a piece of functionality with a special purpose, e.g. rendering a product list or a sign-in form.

An app implements its own rendering functionality (which we will look at later) and then returns the HTML to the paragraph. The paragraph renders its settings along with the app content into the paragraph template and returns the HTML to the Page template. The Page template then renders its own settings along with the HTML that has been returned by all paragraphs on the page, and returns the entire page HTML to the browser.

All sections (app, paragraph, and page) have an output method which outputs the content as a string value. These methods may be extended using notification subscribers, which makes it possible to manipulate the content/output.

Frontend developers can use either HTML tags or ASP.NET Razor to output dynamic content when a page request is being rendered. We strongly recommend using ASP.NET Razor, as this allows you to embed C# code in your templates and access the full power of .NET. Naturally, this also means that you can make things break in much more creative ways, but as they say; with great power comes great responsibility.

Lists of all the tags and loops available in various template contexts are available from the Template Tags area of the documentation portal.

ASP.NET Razor is a server side markup language, which enables you to embed server code (VB & C#) into your templates. It has all the power of .NET, but is easier to use and easier to learn.

Where the formerly used HTML based templates in Dynamicweb have very limited scripting capabilities and requires .NET based add-ins to do more advanced rendering logic, Razor based templates can easily use both the Dynamicweb API and the .NET APIs.

Calling the method @TemplateTags() in a Razor template (.cshtml) will render a list of the tags and loops available from that template context, plus the values assigned to the tag in the present context.

Tag values may then be retrieved and rendered using an appropriate @Get* method:

@GetValue("TagName") @GetString("TagName") @GetInteger("TagName") @GetBoolean("TagName") @GetDouble("TagName") @GetLong("TagName") @GetDate("TagName")

The @Get*-methods return safe values – GetInteger will always return a valid integer, GetString will return a string, and so forth. When you retrieve an object of a particular data type, you can use the .NET data type methods on it out of the box. If the passed tag name does not exist or does not match the data type of the @Get method, it will return 0.

If any loops are available in the template context, they can be used to iterate through content:

@foreach (LoopItem i in GetLoop("LoopName")) { //Do Stuff }

And of course you also have access to conditional statements, e.g.:

@if (GetString("TagName") == "Value") { text to print if condition is met } else if (GetString("TagName") == "Value") { text to print if condition is met } else { text to print }

A view model is an object which can be rendered in a view – a Razor template. The view model represents an entity – such as a page or a paragraph – and has been optimized for frontend rendering.

Since view models are objects with strongly typed properties, you will be able to use intellisense in Visual Studio to easily find available values (Figure 6.1).

Figure 6.1 using ViewModels makes it possible to use intellisense

In order to use a view model the template must inherit from ViewModelTemplate and should specify a model that is valid in the context where the template is used, e.g. page or paragraph. The type of view model should be specified at the top of the template:

@inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>

Another very useful feature when doing frontend development in Dynamicweb is the ability to publish content to feeds.

Dynamicweb contains a number of apps – e.g. the product catalog app, the item publisher app, or the shopping cart app – which is used to publish various types of content, and that content can easily be published as for instance a JSON feed or an XML feed.

A very simple approach to creating a feed could be:

  • Create a page for the feed and attach an appropriate app to it – e.g. a product catalog app
  • Use an app template to loop through content and render it in an appropriate format – here a product list template:
[ @foreach (LoopItem product in GetLoop("Products")){ if (@product.GetInteger("Ecom:Product.LoopCounter") > 1){<text>,</text>} <text>{ "id": "@product.GetString("Ecom:Product.ID")", "name": "@product.GetString("Ecom:Product.Name")", "number": "@product.GetString("Ecom:Product.Number")", "price": "@product.GetString("Ecom:Product.Price")", "link": "@product.GetString("Ecom:Product.LinkGroup.Clean")", "variantid": "@product.GetString("Ecom:Product.VariantID")", "image": "@product.GetString("Ecom:Product.ImageSmall.Clean")" }</text>} ]
  • Go to page properties and open the Layout tab, then select or create a layout template which doesn’t include any master page markup, etc.
<div class="dwcontent" id="content-main" title="Main content" data-settings="unwrap: true; template:moduleonly.html"></div>
  • Select an appropriate content type (Figure 7.3)
Figure 7.3 Selecting a content type for the page

The example above produces a feed in the following format:

[{ "id": "PROD1", "name": "Allspice", "number": "1", "price": "$11.00", "link": "Default.aspx?ID=2&GroupID=GROUP2&ProductID=PROD1", "variantid": "", "image": "/Files/Images/Spices/1.jpg" },{ "id": "PROD2", "name": "Basil", "number": "2", "price": "$110.00", "link": "Default.aspx?ID=2&GroupID=GROUP2&ProductID=PROD2", "variantid": "", "image": "/Files/Images/Spices/2.jpg" }]

Feeds like these can be used (and abused) for any number of purposes, but are primarily useful if you have content areas where you want to update only a smaller part of the page, e.g. a mini cart or a cart counter.

And if you use JS templating engines – like mustache.js and handlebars.js – feeds are pretty much the perfect data source.

In this tutorial, you’ve learned about:

  • The template hierarchy and the basic process when a website is rendered
  • The basics of frontend development in Dynamicweb, including Razor, View Models & how to publish content to feeds

In the next tutorial we will get back to extensibility, but this time in a more concrete manner; by looking at how you can extend the Ecommerce area of Dynamicweb with a notification subscriber, a custom price provider, and a custom sales discount provider (using configurable add-ins).