Table of Contents

UI view properties

Type of UI view property

There are several types of property:

  • A property bound to an entity view property
  • A property bound to an entity view property with getter
  • An unbound property
  • An unbound .NET type property

A bound property will be sent to the server on save unlike an unbound property.

Property bound to an entity view property

The property will be sent to the server on save.

Property bound to an entity view property with getter

The property will be sent to the server on save.

On an entity view, a property can have a getter. If the UI view property is bound to the entity view property with getter, the getter will be transpiled so that it can be evaluated on the client side.

Unbound property

The property will not be sent to the server on save.

It is limited to standard Neos data types.

It can be visible to the user (e.g. in a datagrid or bound to a form field).

With getter and setter

An unbound property can have a getter and a setter.

A property with getter allows you to have a calculated property (on the client side) based on the item itself. For example, to concatenate two properties:

return Item.LastName + " " + Item.FirstName;

A property with getter is read only but it is possible to add a setter on the property to make it editable. For example, to set multiple properties from the value:

if (value != null)
{
    string[]? nameParts = value.Split(" ");
    Item.LastName = nameParts.ElementAtOrDefault(0);
    Item.FirstName = nameParts.ElementAtOrDefault(1)
}
else
{
    Item.LastName = null;
    Item.FirstName = null;
}
Reactivity in datagrid

In most cases, a property with getter will be automatically reactive in the datagrid. However, there are particular cases where it's not. If you are experiencing a responsiveness problem in the datagrid linked to an expression (getter, format, etc.), you can consult this article.

Unbound .NET type property

The property will not be sent to the server on save.

It is not limited to standard Neos data types. It can only be of a transpilable .NET type (e.g. a data object).

It can have a getter and a setter.

It cannot be displayed to the user (e.g. visible in the data grid or bound to a form field).

It is useful internally for storing complex data by property. It avoids having a Dictionary UI view field that stores the complex data for each element of the data source.

Attributes

Character casing

The character casing of the property applied to the string content. By default, this value is inherited from the entity property or the entity view property.

Unlike on the server side, the definition of this attribute will not be translated by a control but by an automatic conversion of the text :

  • lower casing / UPPER CASING : characters are converted to upper/lower case automatically as you type
  • camelCasing / PascalCasing : the full text will be converted to camelCase or PascalCase when you leave the input field
Note

If the value displayed in a lookup has a character casing, it will also be applied when searching the list of values. This only applies to the lower and upper casing.

Format

This attribute allows you to format the value (number or date and time) of the property. It is possible to define a constant in the entity property. On the UI view side, the format can be defined as an expression. Here is an example of an expression for adding a prefix and suffix to a decimal property value :

  return Item != null ? $"\"Total amount: \" {Property.GetDecimalFormat(Item)}  \"{Item.Currency}\"" : Property.GetDecimalFormat(Item);
  • Property is the property that allows access to the UI view property on which the expression is defined.
  • GetDecimalFormat(Item) is a method that retrieves the format of a decimal constructed from the scale defined on the property. Here, the scale is retrieved from user input.
Warning

If you use a property not known by the datagrid, it's necessary to force the reactivity of the property. To see more details, you can consult the following article. In this case, if the currency is not displayed in the datagrid, the reactivity will not be automatically triggered without this code (defined in the view UI initialization event):

Properties.FormattedAmount.EnableWatcher();
Note

A screen illustrates this functionality in technical demos : Format expression.

You can also obtain the formatted value in UI code using the GetFormattedValue method on the UI view property. For example, in a Computed that will be used in the template :

return DatasourceCurrent != null ? Properties.FormattedAmount.GetFormattedValue(DatasourceCurrent) : null;

White space handling

The white space handling of the property applies to strings and localizable strings. By default, this value is inherited from the entity property or the entity view property.

Unlike on the server side, the definition of this attribute will not be translated by a control but by an automatic conversion of the text:

  • no leading and trailing white space: removes any leading and trailing white spaces from the input value. It ensures that the text entered in the textbox does not start or end with white spaces.
  • no leading white space: removes any leading white spaces from the input value. It ensures that the text entered in the textbox does not start with white spaces.
  • no trailing white space: removes any trailing white spaces from the input value. It ensures that the text entered in the textbox does not end with white spaces.
  • no white space: removes all white spaces from the input value. It ensures that the text entered in the textbox does not contain any white spaces at all.

Multiline

For String and LocalizableString properties, a UI view property should stay consistent with its source entity view property.

  • If a UI view property is configured with Multiline = true while its source entity view property is not multiline, generation logs warning M0068 (PropertyCannotBeMultilineBecauseSourceIsNot).
  • If a multiline-oriented template component is bound to a single-line UI view property, generation logs warning M0067 (ElementBoundToNonMultilineProperty). This applies to rich-text-editor, expression-editor, code-editor, and markdown-viewer.
Important

These warnings should be treated as migration and quality priorities. Do not ignore or downgrade them globally: align Multiline across entity, entity view, UI view, and template usage to avoid runtime inconsistencies.

Total summary type

The Total summary type attribute allows you to automatically display the total summary of the property in the footer of the datagrid. See Datagrid documentation for more information.

It is possible to load total summaries in UI view code :

SummaryRequest productNameRequest = new(Properties.Name, SummaryType.Count);
SummaryRequest quantityMinRequest = new(Properties.ID, SummaryType.Min);
SummaryRequest quantityMaxRequest = new(Properties.ID, SummaryType.Max);

ISummaryResult result = await LoadSummariesAsync([productNameRequest, quantityMinRequest, quantityMaxRequest]);

result.TryGetValue(productNameRequest, out object? nameCount);
result.TryGetValue(quantityMinRequest, out object? idMin);
result.TryGetValue(quantityMaxRequest, out object? idMax);

Group summary type

The Group summary type attribute allows you to automatically display the group summary of the property in group rows. See Datagrid documentation for more information.

It is possible to load group summaries in UI view code :

SummaryRequest productNameRequest = new(Properties.Name, SummaryType.Count);
SummaryRequest quantityMinRequest = new(Properties.ID, SummaryType.Min);
SummaryRequest quantityMaxRequest = new(Properties.ID, SummaryType.Max);

IGroupSummaryResult[] results = await LoadGroupSummariesAsync([Properties.Category], [productNameRequest, quantityMinRequest, quantityMaxRequest]);

foreach (IGroupSummaryResult result in results)
{
  string category = (string)result.Key[Properties.Category];
  result.TryGetValue(productNameRequest, out object? nameCount);
  result.TryGetValue(quantityMinRequest, out object? idMin);
  result.TryGetValue(quantityMaxRequest, out object? idMax);
}

Always loaded

By default, every displayable UI view property is requested by every GetAll request (AlwaysLoaded: true). For a read-only list screen with many optional columns, this can mean fetching (and transferring over the network) far more data than what the user is actually looking at.

Setting AlwaysLoaded: false on a UI view property lets the request skip it whenever it is not needed - typically because its column is currently hidden in the datagrid.

Important

AlwaysLoaded cannot be set to false:

  • on the entity view's key property (generation error M0089);
  • on a UI view that allows creating or updating data, i.e. CreationAllowed or UpdateAllowed (generation error M0088).

Set it only on a read-only list UI view.

Deciding whether to load the property

AlwaysLoaded: false only makes the property excludable; it does not decide by itself whether a given request should include it. That decision is entirely up to a Retrieving rule, which sets ShouldLoad on each excludable property before the request is sent:

foreach (var property in GetProperties())
{
    if (!property.AlwaysLoaded)
    {
        property.ShouldLoad = property.DatagridVisible;
    }
}
  • DatagridVisible is the most common condition: load the column only when the user can currently see it.
  • UsedByApplicableUserStyleRule reports whether the property is referenced by a currently applicable user-configured conditional formatting rule (a row-level rule, or a column-level one whose own target column is visible) - combine it with DatagridVisible so a style rule reading a hidden column's value does not silently see stale, never-fetched data:
property.ShouldLoad = property.DatagridVisible || property.UsedByApplicableUserStyleRule;

ShouldLoad has no effect once set on an item already in the datasource; it only changes what the next GetAll request includes.

Reading the property's value

Because the property's value may not have been requested, reading it is restricted to two contexts where a developer legitimately derives a value from other properties: a UIViewProperty Getter, and a Computed's Getter. Reading it anywhere else (an event rule, a Setter, a style rule condition, a property value expression, ...) is a generation-time transpilation error naming the property.

User feedback

When a not-always-loaded column becomes visible without its data (for example because the user just showed it, or a saved custom view surfaces it before the first fetch has caught up), the datagrid shows a dash placeholder in that column and an informational banner offering to refresh; refreshing (from the banner or the toolbar) re-fetches the data with the now-visible column included.

Note

A screen illustrates this functionality in technical demos : UI views > Partial loading (with $select and $expand).

Sort property

Warning

This property is only available through code.

The SortProperty allows you to specify that sorting on one property (e.g., Code) should actually use the value of another property (e.g., SortValue).

Note

Server-side sorting of a bound UI view column requires its source entity view property to be Filterable and to target a single scalar value (not a collection, nor a property where any parent element is originating from a collection). When a sortable bound column does not meet these conditions, generation logs M0077 (UIViewPropertySortableRequiresFilterableEntityViewProperty) and generates the column as non-sortable; in the Designer, the Sortable toggle is read-only for such columns and the stored value is normalized to false. The SortProperty redirection shown above still works: configuring it in code and re-enabling Properties.Code.Sortable = true; applies at runtime, independently of the declarative flag, so the Designer lock does not prevent it. See basic filtering.

Use case

Consider an entity view returning the following data:

ID Code SortValue
1 A100 A100
1 A33 A033
1 A10 A010

In the user interface, we only want to display the ID and Code properties. If a user sorts the table by Code in ascending order, the result would be:

ID Code
1 A10
1 A100
1 A33

This sorting is alphabetical, which causes A100 to appear before A33. However, in our case, the Code always starts with a letter followed by a number, and we want sorting to reflect the numeric value properly.

To achieve this, we precompute and store a SortValue that standardizes the format for correct sorting.

We could expose the SortValue in the table and sort by it directly:

ID Code SortValue
1 A10 A010
1 A33 A033
1 A100 A100

However, to keep the UI clean and uncluttered, we prefer showing only the Code column and linking it internally to SortValue for sorting—whether sorting occurs on the client or the server.

This can be configured during UI initialization in one of the following ways:

If SortValue is part of the model explicitly:

Properties.Code.SortProperty = Properties.SortValue;
Properties.Code.Sortable = true; // re-enable if Code's source is not Filterable (generation/Designer mark it non-sortable)
SetSort("Code", SortDirection.Asc);

Or if SortValue exists in the entity view but is not explicitly in the UI:

Properties.Code.SortProperty = GetProperty("SortValue");
Properties.Code.Sortable = true; // re-enable if Code's source is not Filterable (generation/Designer mark it non-sortable)
SetSort("Code", SortDirection.Asc);

With this configuration:

  • The data will be initially sorted by SortValue when the screen loads.
  • Sorting the Code column in the UI will actually sort by SortValue behind the scenes.

This approach gives you precise control over sorting logic while maintaining a clean and user-friendly interface.