Difference between revisions of "PRS/WebTemplate"

From PRS
Jump to navigation Jump to search
(Created page with "== Introduction == 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 == Fields == === Slug === 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 necessa...")
 
 
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Introduction ==
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.
 
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


== Fields ==
== Fields ==
=== Slug ===
=== 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.
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.


Line 10: Line 8:
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 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.
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 ===
=== Description ===
Line 24: Line 22:
=== Basics ===
=== 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.
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 <code>@</code>, e.g. <code>@employee.Name</code>. If the expression is too complex, surround it with parentheses, <code>@(GenericMethod<string>())</code>. To execute blocks of code, use <code>@{ ... }</code>, and for control structures like <code>if</code> and <code>foreach</code>, the <code>@</code> should come before the keyword, e.g. <code>@if(condition){ ... }</code>.
Within a block of code, one can return to HTML simply by using HTML tags, e.g.
<pre>
@if(condition){
    <p>Condition is true</p>
} else {
    string error = "Condition is false";
    <p>@error</p>
}
</pre>


=== Styling ===
=== Styling ===
Line 29: Line 39:
<code>
<code>
&lt;style&gt;
&lt;style&gt;
@(WebDatabaseInterface.GetStylesheet("MAIN"))
@(WebDatabaseInterface.GetStylesheet("MAIN").Style)
&lt;/style&gt;
&lt;/style&gt;
</code><br>
</code><br>
Line 40: Line 50:
<code>Model.LoadModel(new string[] {"CompanyInformation", "CompanyLogo", "Employee"})</code>.
<code>Model.LoadModel(new string[] {"CompanyInformation", "CompanyLogo", "Employee"})</code>.


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:<br>
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:
<code>
<pre>
Model.LoadModel(<br>
Model.LoadModel(
     new string[] {"CompanyInformation", "CompanyLogo", "Employee"},
     new string[] {"CompanyInformation", "CompanyLogo", "Employee"},
     new DataModelQueryDef<Employee>(
     new DataModelQueryDef<Employee>(
Line 49: Line 59:
         null)
         null)
)
)
</code><br>
</pre><br>
By default, all columns in the database are loaded, so this is a way to drastically reduce the amount of data loaded.
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 <code>null</code>, specify a filter and sort order for the retrieved data.)
(The other two fields, set to <code>null</code>, specify a filter and sort order for the retrieved data.)
==== Retrieving Data ====
To get a table that has been loaded, use <code>Model.GetTable<T>(alias)</code>. This returns an object of type <code>CoreTable</code>, which has a property <code>Rows</code>, through which one can retrieve data. An example is shown here.
<pre>
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>
}
</pre>


=== Partial Templates ===
=== 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:
<pre>
<header>
    <h1>The Title</h1>
</header>
</pre>
Then, within the main page, call <code>@Raw(WebHandler.RunTemplate(WebDatabaseInterface.GetWebTemplateBySlug("header"), Model))</code>
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.

Latest revision as of 07:33, 18 August 2022

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[edit | edit source]

DataModel[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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.

Visible[edit | edit source]

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


Writing a Template[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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[edit | edit source]

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.