Pipes
Pipes are an important concept in PBars that have been strongly inspired by Markup.js. The idea behind pipes is, that values can be processed in a standard way providing a simple extension mechanism. Pipes conceptually work like pipes in dos/unix shells. You put values in and get transformed values out. Here is a simple example of how to use a pipe in a data expression:
Template:
{{FirstName | ToUpper}}
Pipes are delimited by the | character and individually evaluated. The above template will take the value of the FirstName
field, send it as an input to the ToUpper
pipe and return the output. You can concatenate as many pipes as you like.
Template:
{{FirstName | ToUpper | Trim}}
Pipe parameters
Pipes may also be parameterized.
Template:
{{FirstName | PadRight 20}}
Each pipe defines it's parameters. Pipes parameters are delimited by spaces. If a parameter value has spaces, it can be quoted (the outer quoutes will be removed), either by using "
or '
characters. The other quote character can then be used in the string.
PBars distinguishes in between literals and data context parameters. A literal parameter is just a string (like "20" in the prior example). Data context parameters point to a value in the data context (see Data expressions in the basics section).
Pipes define a preference, how to interprete a parameter. In addition parameters can explicitly be marked as literals or data expressions.
A template expression does not explicitly state, that the first parameter. It assumes, that it's a literal.
{{#template SubTemplate.txt}}
Making it an explicit literal would look like this:
{{#template "SubTemplate.txt"}}
You could also explicitly say, that the parameter is not a literal, but a data expression by putting it in square brackets:
{{#template [TemplateName]}}
Predefined pipes
PBars comes with a fair amount of standard pipes out of the box and it's quite easy to implement your own (this will be discussed in a later chapter).
Aggregates
Count
Returns the number of elements in a collection.
{{People | Count}}
Even
Returns true
for even elements in a collection and false
for odd ones.
{{#each People}}
{{(this) | Even}}
{{/each}}
Odd
Returns true
for odd elements in a collection and false
for even ones.
{{#each People}}
{{(this) | Even}}
{{/each}}
IsFirst
Returns true
for the first element in a collection, otherwise false
.
{{#each People}}
{{(this) | IsFirst}}
{{/each}}
IsLast
Returns true
for the last element in a collection, otherwise false
.
{{#each People}}
{{(this) | IsLast}}
{{/each}}
Reverse
Returns the collection in reverse order.
{{#each People | Reverse}}
{{FirstName}}
{{/each}}
Strings
PadLeft
Fills a string with a character (by default space) on the left side, until it reaches the given length.
{{FirstName | PadLeft 20}}
To specify another character, specify it behind the string length:
{{FirstName | PadLeft 20 _}}
You can optionally specify to truncate the string if it is longe than the indended length:
{{FirstName | PadLeft 20 _ truncate}}
PadRight
Fills a string with a character (by default space) on the right side, until it reaches the given length.
{{FirstName | PadRight 20}}
To specify another character, specify it behind the string length:
{{FirstName | PadRight 20 _}}
You can optionally specify to truncate the string if it is longe than the indended length:
{{FirstName | PadRight 20 _ truncate}}
Center
Fills a string with a character (by default space) on the left/right side, until it reaches the given length, effectively centering the string.
{{FirstName | Center 20}}
To specify another character, specify it behind the string length:
{{FirstName | Center 20 _}}
ToLower
Converts a string to lower case.
{{FirstName | ToLower}}
ToUpper
Converts a string to upper case.
{{FirstName | ToLower}}
TrimLeft
Removes spaces on the left hand side of the string.
{{FirstName | TrimLeft}}
TrimRight
Removes spaces on the right hand side of the string.
{{FirstName | TrimRight}}
Trim
Removes spaces on the left and right hand side of the string.
{{FirstName | Trim}}
Other
Not
Inverts the value of a boolean.
{{#IsPublished | Not}}
Truesy
Converts a type to a boolean. The logic here is:
- For strings
- empty string =>
false
, any other =>true
- empty string =>
- For numbers
- 0 =>
false
, any other =>true
- 0 =>
- For collections
- empty collection =>
fals
, any other =>true
- empty collection =>
- For any other object
- if NULL
false
, otherwisetrue
- if NULL
Converters
By default, PBars will use the .ToString()
method on values that are not string to get the string representation. This may make sense in many cases, however when it comes to dates, decimal numbers and booleans, it makes more sense to perform explicit formatting. For this, the concept of converters comes into play.
It converter is a specialized pipe, that is annotated with the type that it converts from and the name. All converters can be called without explicit parameters, most however offer additional parameters.
By default - converters are registered for most primitive types. In addition you can add your own and replace existing ones. The CompilerOptions
class has a property ConverterSettings
that specifies the behavior of the default converters.
In addition to implicitly using converters you can just specify them as explit pipes like this:
{{#Price | DecimalConverter}}
Number converters
Format strings are in the format used in string.Format:
string.Format("{0:FormatString}",value)
The culture specified in the ConverterSettings
is used (defaults to CultureInfo.CurrentCulture
).
Name | Source type | Parameters |
---|---|---|
DoubleConverter | double | format string (string.format); otherwise uses ConverterSettings.DecimalFormatString . |
ByteConverter | byte | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
DecimalConverter | decimal | format string (string.format); otherwise uses ConverterSettings.DecimalFormatString . |
FloatConverter | float | format string (string.format); otherwise uses ConverterSettings.DecimalFormatString . |
IntegerConverter | integer | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
LongConverter | long | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
SByteConvter | sbyte | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
ShortConverter | short | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
UIntConverter | uint | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
ULongConverter | ulong | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
UshortConverter | ushort | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
LongConverter | long | format string (string.format); otherwise uses ConverterSettings.IntegerFormatString . |
Date / time converters
Format strings are in the format used in string.Format:
string.Format("{0:FormatString}",value)
The culture specified in the ConverterSettings
is used (defaults to CultureInfo.CurrentCulture
).
Name | Source type | Parameters |
---|---|---|
DateTimeConverter | DateTime | format string (string.format); otherwise uses ConverterSettings.DateTimeFormatString . |
DateTimeOffsetConverter | DateTimeOffset | format string (string.format); otherwise uses ConverterSettings.DateTimeOffsetFormatString . |
TimeSpanConverter | TimeSpan | format string (string.format); otherwise uses ConverterSettings.TimeSpanFormatString . |
Other converters
Format strings are in the format used in string.Format: string.Format("{0:FormatString}",value)
Name | Source type | Parameters |
---|---|---|
GuidConverter | Guid | format string (string.format); otherwise uses ConverterSettings.GuidFormatString . |
BooleanConverter | bool | True display text, False display text; otherwise uses settings from ConverterSettings . |
Encoders
Encoders allow to process the result of data expressions before rendering it to output. The most obvious use case here is HTML encoding. Encoders themselves are regular pipes. Predefines encoders are: HtmlEncode
and UrlEncode
. If you are using an auto encoder (next section). You need to combine the explicit encoding with the Raw
pipe to prevent doulbe encoding.
Auto encoder
By default PBars does not assume that you want to safely encode for usage in HTML or any other markup style. However you can register an auto encoder which is applied against the output of data expressions before they are rendered into the document. Auto encoding happens at the end of the pipeline (after converters). If you want automatic HTML encoding, you may set the encoder on the CompilerOptions
.
As you may have already guessed, an autoencoder is just a pipe itself.
compilerOptions.AutoEncoder = new HtmlEncodePipe();
If you want to suppress the auto encoder explicitly, use the Raw
pipe.
{{HtmlMarkup | Raw}
Nested templates and template registries
As shown in the basic usage section, templates can be nested using the {{#template}}
directive. To be able make use of nested templates, you need to provide a template registry. Template names use a forward slash as a path delimiter and should alway have a file extension. The template registry is set on the CompilerOptions
. Templates are only compiled once. Meaning you do not have a performance hit, when using the same template multiple times.
PBars comes with two template registry implementations out of the box:
FileSystem
This registry will pull templates off the file system. The path will be translated relative to a given root directory.
compilerOptions.TemplateRegistry = new FileSystemTemplateRegistry(@"c:\");
This will set the root path of the registry to c:\
. Let's assume, we embed a template like this:
{{#template myTemplates/template.txt}}
In this case the template registry will resolve to c:\myTemplates\template.txt
.
EmbeddedResource
This registry will read templates from embedded resources inside an assembly. When initializing, you specify a "marker type", that defines the assembly and the root namespaces of all templates. Slashes will be translated to . effectively nesting namespaces.
compilerOptions.TemplateRegistry = new EmbeddedResourceTemplateRegistry(typeof(MarkerClass);
Assuming this template directive, template.txt will be pulled off the namespave below the MarkerClass
type.
{{#template myTemplates/template.txt}}
- MarkerClass.cs (type)
- myTemplates (folder)
- template.txt (embedded resource)
- myTemplates (folder)