Table of Contents

View model

What is the view model?

In the MVVM (Model-View-ViewModel) design pattern used by Neos UI views and UI components, the view model is the intermediary component that manages data bindings between the model (data layer) and the view (template).

graph LR
    A[Model<br/>Data from entity view or server method] <--> B[ViewModel<br/>Data bindings and UI logic]
    B <--> C[View<br/>XML Template]

The view model provides:

  • Data binding: Synchronizes data between the model and the view
  • UI logic: Methods, computeds, fields, and event rules
  • User interaction: Built-in methods for displaying messages, toasts, file selection, and navigation

Accessing the view model

In UI code (event rules, methods, actions, computeds), you have implicit access to the view model through the this keyword. Most view model methods can be called directly.

// In an event rule or method
// UIResources.Sales.OrderSavedTitle (Scope=Frontend) => "Success"
// UIResources.Sales.OrderSavedMessage (Scope=Frontend) => "The order has been saved successfully."
ShowToast(MessageType.Positive, UIResources.Sales.OrderSavedTitle, UIResources.Sales.OrderSavedMessage);

Built-in view model methods

The view model inherits several methods that are available in all UI views and UI components. These methods provide common functionalities for user interaction.

For the complete API reference, see IBaseViewModel.

Display a message dialog

Use ShowMessageAsync to display a modal dialog box and wait for the user's response. The method returns an IMessageResponse containing the clicked button.

The dialog appearance is controlled by the MessageType enumeration (Info, Positive, Warning, Danger).

Buttons are defined using MessageButton which accepts either a MessageButtonType (Yes, No, OK, Cancel) or custom identifiers.

Important

Always source the title and message text from localized UI resources (UIResources.<Module>.<Key>, backed by a StringResource with Scope=Frontend) rather than hard-coded literals, so dialogs and toasts stay translatable. UIResources.Sales.* and UIResources.Core.* in the examples below are illustrative — replace them with your own module's keys. See String resources for details.

Example - Confirmation with standard buttons:

// UIResources.Sales.ConfirmDeletionTitle (Scope=Frontend) => "Confirm deletion"
// UIResources.Sales.ConfirmDeletionMessage (Scope=Frontend) => "Are you sure you want to delete this order? This action cannot be undone."
IMessageResponse result = await ShowMessageAsync(
    MessageType.Warning,
    UIResources.Sales.ConfirmDeletionTitle,
    UIResources.Sales.ConfirmDeletionMessage,
    new MessageButton(MessageButtonType.Yes),
    new MessageButton(MessageButtonType.No));

if (result.ButtonType == MessageButtonType.Yes)
{
    // Proceed with deletion
}

Example - Custom buttons:

// UIResources.Sales.ExportFormatTitle (Scope=Frontend) => "Export format"
// UIResources.Sales.ExportFormatMessage (Scope=Frontend) => "Choose the format for the export:"
IMessageResponse result = await ShowMessageAsync(
    MessageType.Info,
    UIResources.Sales.ExportFormatTitle,
    UIResources.Sales.ExportFormatMessage,
    new MessageButton(0, "PDF"),
    new MessageButton(1, "Excel"),
    new MessageButton(2, "CSV"),
    new MessageButton(MessageButtonType.Cancel));

if (result.ButtonType == MessageButtonType.Custom)
{
    int? formatId = result.ButtonCustomId; // 0 = PDF, 1 = Excel, 2 = CSV
}

Display a message dialog with input

Use ShowMessageWithInputAsync to display a modal dialog box with an input field. You can provide an optional validation function that returns an error message when the input is invalid.

The user's input is available in the response via InputValue.

Example - Input with validation:

// UIResources.Sales.CloneOrderTitle (Scope=Frontend) => "Clone order"
// UIResources.Sales.CloneOrderMessage (Scope=Frontend) => "Enter a name for the cloned order:"
// UIResources.Sales.OrderNameRequiredError (Scope=Frontend) => "Order name is required"
IMessageResponse response = await ShowMessageWithInputAsync(
    MessageType.Info,
    UIResources.Sales.CloneOrderTitle,
    UIResources.Sales.CloneOrderMessage,
    input => string.IsNullOrWhiteSpace(input) ? UIResources.Sales.OrderNameRequiredError : null,
    new MessageButton(MessageButtonType.OK),
    new MessageButton(MessageButtonType.Cancel));

if (response.ButtonType == MessageButtonType.OK)
{
    string newOrderName = response.InputValue!;
    await CloneOrderAsync(newOrderName);
}

Display a toast notification

Use ShowToast to display a temporary notification at the bottom-right corner of the screen.

You can customize the duration (default 3000ms), whether the toast is dismissible, and add action buttons using ToastButton.

Note

Toasts displayed using ShowToast do not appear in the notification center and are not affected by the "Do not disturb" mode.

Example - Simple toast:

// UIResources.Sales.ChangesSavedTitle (Scope=Frontend) => "Success"
// UIResources.Sales.ChangesSavedMessage (Scope=Frontend) => "The changes have been saved."
ShowToast(MessageType.Positive, UIResources.Sales.ChangesSavedTitle, UIResources.Sales.ChangesSavedMessage);

Example - Persistent toast (no auto-close):

// UIResources.Core.ConnectionLostTitle (Scope=Frontend) => "Connection lost"
// UIResources.Core.ConnectionLostMessage (Scope=Frontend) => "You are currently offline. Changes will be saved when connection is restored."
ShowToast(MessageType.Warning, UIResources.Core.ConnectionLostTitle, UIResources.Core.ConnectionLostMessage, null);
Note

Setting the duration parameter to null or 0 disables auto-close, requiring the user to dismiss the toast manually.

Example - Toast with action buttons:

// UIResources.Sales.NewOrderReceivedTitle (Scope=Frontend) => "New order received"
// UIResources.Sales.NewOrderReceivedMessage (Scope=Frontend) => "Order #{0} has been placed by {1}."
ShowToast(
    MessageType.Info,
    UIResources.Sales.NewOrderReceivedTitle,
    string.Format(UIResources.Sales.NewOrderReceivedMessage, 12345, "Customer ABC"),
    5000,
    true,
    new ToastButton("View order", "eye", () => NavigateToOrder(12345)));

Display an error

Use ShowError to display an error message based on an exception.

Example:

try
{
    await SomeRiskyOperationAsync();
}
catch (Exception ex)
{
    ShowError(ex);
}

Select and upload a file

Use SelectFileAsync to open a file picker dialog and immediately upload the selected file. You can specify accepted file types (MIME types or extensions) and an optional maximum file size.

For more details on how file and image uploads work in UI views, see Image data type.

Example:

int maxSize = 10 * 1024 * 1024; // 10 MB
FileReference? file = await SelectFileAsync(maxSize, ".pdf", ".docx", "image/*");
if (file != null)
{
    string fileName = file.FileName;
}

Select a file with deferred upload

Use SelectDeferredFileAsync to open a file picker dialog but defer the upload. This is useful when you need to upload the file later or as part of a larger operation (e.g., when saving an entity).

For a detailed explanation of the deferred upload workflow, see Image data type.

Example:

DeferredFileReference? file = await SelectDeferredFileAsync(".xlsx", ".csv");
if (file != null)
{    
    Item.Picture2 = file; // Uploaded when calling StartUpload()
    file.WithCallback(fileReference => {
        // Optional method called when uploading succeeds or fails
    });
    file.StartUpload();
}

Toggle an overlay

Use ToggleOverlay to open or close an overlay (modal or popover) by its identifier.

Example:

ToggleOverlay("myModalId");

Access the main view model

Use GetMainViewModel to retrieve the root view model of the current view hierarchy. This is useful when you need to access any element of the main view model (datasource, methods, fields, computeds, etc.) from a sub-view or UI component.

Example:

OrderUIViewModel mainViewModel = (OrderUIViewModel)GetMainViewModel<OrderUI>();
string orderNumber = mainViewModel.DatasourceCurrent!.OrderNumber;
mainViewModel.Fields.IsEditing = true;

Access the parent view model

Use GetParentViewModel to retrieve the parent view model. This is useful in sub-views and UI components to access any element of the parent view model (datasource, methods, fields, computeds, etc.).

Example:

OrderUIViewModel? parentViewModel = (OrderUIViewModel?)GetParentViewModel<OrderUI>();
if (parentViewModel != null)
{
    parentViewModel.Methods.RefreshData();
}

Retrieve an enumeration dynamically

Use GetEnum or FindEnum to retrieve an enumeration type by name at runtime. GetEnum throws an exception if not found, while FindEnum returns null.

Example:

Neos.Designer.UIAbstractions.Enums.IEnumType statusEnum = GetEnum("OrderStatus");
foreach (Neos.Designer.UIAbstractions.Enums.IEnumMember member in statusEnum.GetEnumMembers())
{
    // Process enum members
}
Tip

When you know the enumeration type at compile time, prefer using type-safe alternatives:

  • From a UI view property: Properties.Unit.Enum.Kg or Properties.Unit.GetEnumMember("Kg")
  • From the Enums property: Enums.ProductUnit.Kg or Enums.ProductUnit.GetEnumMember("Kg")

These approaches provide IntelliSense support and compile-time validation. For more details, see Retrieve enum member metadata.

Export server data

Use ExportServerDataAsync to export data from the server using the specified options.

For detailed information about export server data, see Server data exporting.

See also