Web Template

From PRS
Revision as of 02:13, 16 December 2022 by Kenric (talk | contribs) (→‎Visible)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Web Templates are the manner in which the Web Engine interfaces with a user, written in HTML with C# support using the Razor templating engine. Upon receiving a request from a user, the WebEngine finds the template that is required and then executes it, recompiling if changes have been made.

Fields

DataModel

The DataModel field is a name of an entity type, such as Equipment or Employee, which specifies the specific data to load for the page template. For example, if you are writing a page which lists employees, it is useful to preload the data necessary - this is done by setting DataModel to "Employee". This field is optional.

Slug

The Slug field denotes the name of the page itself, intended to be a short text field which describes the function of the page. Note that it cannot contain any slashes ('/', '\'), and should use only characters which are URL-safe; when in doubt, stick to just numbers and letters.

The DataModel and slug fields combine to form a path to the page, with the form www.domain.com/v1/DataModel/Slug?id=XXXXXXXX-XXXX-XXXX-XXXXXXXX. If the DataModel field is empty, then the URL is simply www.domain.com/v1/Slug. This allows you to create pages which do not have to be tied to a specific entity. If a page has a DataModel and the id query does not match any page, then a 404 Not Found is returned to the user.

Description

The Description field is a non-functional field which allows you to add a description to the template - this is not necessary, but can be useful as a reference.

Template

The source code for the template, which is in the Razor syntax - a mix of C# and HTML.

Visible

The Visible field denotes whether the page is accessibly via a URL - if it is not visible, then a 404 Not Found is returned when trying to access it - it is as if it didn't exist. Use this if you want to disable a page or if the template is only relevant in the context of other templates - see Partial Templates

Root URL

This field is default to false. It defines whether the URL of the page is a root URL, or whether it is prefixed by "v1/" (The default is the prefix). We have the prefix so that we can add our own endpoints to the Web Engine, such as the "/login" endpoint, without clashing with any endpoints that you have created. However, if you do want to remove the prefix, untick this box. In order to allow you to choose a URL which is guaranteed to never clash with our own endpoints, you can start your slug with a capital letter - we reserve all lowercase letter slugs that are not prefixed with "v1/".

Tick this box at your own risk, since if we add an endpoint in future that has the same name as a page you have added, your page will effectively become inaccessible.

Writing a Template

To write a template, you should be familiar with HTML, CSS and JavaScript as well as C#, which is used for non-static content.

Basics

At its base, a template is an HTML file - that is, that one can write a static web page, without the use of C#, and it would display as it would in a browser. Note that this has no means of accessing any resources outside of the page, so any styling with CSS must be embedded.

The page is then able to contain embedded C# code, using the Razor syntax. Roughly, one can embed a C# expression by preceding it with an @, e.g. @employee.Name. If the expression is too complex, surround it with parentheses, @(GenericMethod<string>()). To execute blocks of code, use @{ ... }, and for control structures like if and foreach, the @ should come before the keyword, e.g. @if(condition){ ... }.

Within a block of code, one can return to HTML simply by using HTML tags, e.g.

@if(condition){
    <p>Condition is true</p>
} else {
    string error = "Condition is false";
    <p>@error</p>
}

Styling

To add a stylesheet, you can create a WebStyle, which can be loaded with WebDatabaseInterface.GetStylesheet(string code), which retrieves the content of that stylesheet as raw text. Thus, to use a WebStyle with the code "MAIN", one would put in the <head> tag:

<style> @(WebDatabaseInterface.GetStylesheet("MAIN").Style) </style>

This would load that stylesheet into the current web page.

If multiple stylesheets need to be loaded, consider using WebDatabaseInterface.GetStylesheets(params string[] stylesheetCodes), which gets all the stylesheets in request.

Using DataModels

The Razor engine provides to each template page a parameter called Model, by which data can be retrieved. By default, it contains no data except for a table called "User", which contains the current user. To load the required data for the page, a call to Model.LoadModel(string[] requiredTables, params IDataModelQueryDef[] requiredQueries) must be executed.

The first parameter, requiredTables, specifies which tables should be loaded. By default, LoadModel loads nothing. In general, the CompanyInformation, CompanyLogo and the current entity are useful to load, so a call could look like:

Model.LoadModel(new string[] {"CompanyInformation", "CompanyLogo", "Employee"}).

The second parameter specifies a way to narrow the load of the data, preventing unnecessary data from being loaded. For example, if one only requires the ID and Name fields of an employee, one might call:

Model.LoadModel(
    new string[] {"CompanyInformation", "CompanyLogo", "Employee"},
    new DataModelQueryDef<Employee>(
        null,
        new Columns<Employee>(x => x.ID).Add(x => x.Name),
        null)
)


By default, all columns in the database are loaded, so this is a way to drastically reduce the amount of data loaded. (The other two fields, set to null, specify a filter and sort order for the retrieved data.)

Retrieving Data

To get a table that has been loaded, use Model.GetTable<T>(alias). This returns an object of type CoreTable, which has a property Rows, through which one can retrieve data. An example is shown here.

Model.LoadModel(new string[] {"Employee"}); // Load Model
CoreTable employeeTable = Model.GetTable<Employee>(); // Get Table from Model

// Iterate through the rows
foreach(CoreRow row in employeeTable.Rows){
    // Convert the row to an Employee. This is not necessary, and the data can also be retrieved with row[ColumnName] or row.ToDictionary()[ColumnName]
    var employee = row.ToObject<Employee>();
    <p>@employee.ID: @employee.Name</p>
}

Partial Templates

Sometimes it is useful to write a partial template, that is, one that only represents part of a web page and is used elsewhere, e.g. a header which is used site-wide. This is possible. First, create a web template with the Visible property unchecked. Leave the DataModel blank, since that is only useful when loading the page from an HTTP request. For this example, give it the Slug header, and set its content to be:

<header>
    <h1>The Title</h1>
</header>

Then, within the main page, call @Raw(WebHandler.RunTemplate(WebDatabaseInterface.GetWebTemplateBySlug("header"), Model))

Through this, the header will be inserted into the main page. Note that @Raw is required, for otherwise the retrieved HTML will be displayed as plain text, rather than interpreted as HTML.

This method can also be used for loading stylesheets which must load styling information non-statically. Simply save the stylesheet as a WebTemplate instead of as a WebStyle, and the load it as a template.