Hack: 100 in 1 Report – Dynamic Report Layout Selection

In this video, I show how to create a report where the users can select a layout when printing the report. Making it possible to have many different layouts on the same report.


In this video, Erik demonstrates a clever technique for creating a single report object in Business Central that can serve as hundreds of different reports by leveraging dynamic custom report layouts. Instead of duplicating report objects with identical datasets, you attach multiple Word (or RDLC) layouts to one report and let users choose which layout to use at runtime.

Understanding the Concept

A report in Business Central consists of two separate components:

  1. The Report Object — the business logic that produces a dataset
  2. The Layout — which consumes the dataset and renders it as a PDF, Word document, etc.

Business Central has the powerful ability to switch layouts on-the-fly. This video exploits that feature to create one report with an unlimited number of layouts attached to it. Users can select which layout they want each time they run the report — no developer intervention required for new layouts.

Creating the Base Report

Erik starts by creating a report using the AL File Wizard (from the AZ AL Dev Tools extension for VS Code). The report runs on the Customer table and includes all available fields as columns in the dataset. A few obsolete fields that throw warnings are removed (fields marked for removal like the old text-based display name, the legacy ID field replaced by SystemId, and the Picture blob replaced by the Image media set field).

The key properties on the report are:

report 50123 "Multi Report"
{
    UsageCategory = ReportsAndAnalysis;
    ApplicationArea = All;
    dataset
    {
        dataitem(Customer; Customer)
        {
            // All customer columns defined here...
        }
    }
}

At this stage, the report has no layout attached, so running it produces a completely blank PDF — exactly what you’d expect.

Custom Report Layouts

The magic happens in the Custom Report Layouts page in Business Central. You can attach multiple Word or RDLC layouts to a single report object. Each layout has a unique Code as its primary key, which follows the pattern of the report number followed by a sequence (e.g., 50123-000001, 50123-000002, etc.). You can verify this using the Page Inspector.

Erik had pre-created two Word layouts for demonstration. When running the report from the Custom Report Layouts page and selecting different layouts, each renders with its own unique design — proving the concept works.

The Key Trick: OnInitReport Trigger

The core of this hack is incorporating the layout selection directly into the report’s execution flow. The OnInitReport trigger is the very first trigger that fires when a report object runs, and it’s the last opportunity to change the layout before the report proceeds. Once you pass this trigger, whatever layout is selected becomes locked in.

To set the layout programmatically, you use the Report Layout Selection table and its SetTempLayoutSelected function:

trigger OnInitReport()
var
    RLS: Record "Report Layout Selection";
begin
    Layout.Setrange("Report ID", 50123);
    if page.RunModal(50123, Layout) = action::LookupOK then
        RLS.SetTempLayoutSelected(Layout.Code)
    else
        error('Please select a layout to continue!');
end;

var
    Layout: Record "Custom Report Layout";

Note that Layout is declared as a global variable — something Erik rarely does — but it’s justified here because the variable is set in the OnInitReport trigger and also displayed on the request page to show users which layout they’ve selected.

The flow is straightforward:

  1. Filter the Custom Report Layout table to only show layouts for this report
  2. Open a modal page for the user to pick a layout
  3. If they select one, call SetTempLayoutSelected with the layout’s Code
  4. If they cancel, show an error to stop execution

The Layout Selection Page

To present users with a clean selection experience, Erik creates a simple list page sourced from the Custom Report Layout table:

page 50123 "Select Layout"
{
    PageType = List;
    UsageCategory = None;
    SourceTable = "Custom Report Layout";
    Editable = false;
    layout
    {
        area(Content)
        {
            repeater(Rep)
            {
                field(Description; Description)
                {
                    ApplicationArea = all;
                }
            }
        }
    }
    actions
    {
        area(Processing)
        {
            action(EditLayout)
            {
                Caption = 'Edit Layouts';
                ApplicationArea = All;
                Image = DocumentEdit;
                ToolTip = 'Edit the report layouts';
                RunObject = Page "Custom Report Layouts";
                RunPageLink = "Report ID" = field("Report ID");
                Promoted = true;
                PromotedCategory = Process;
                PromotedIsBig = true;
                PromotedOnly = true;
            }
        }
    }
}

The page shows only the description of each layout, keeping it simple for end users. The Edit Layouts action opens the standard Custom Report Layouts page filtered to this report, allowing users to create, import, and export layouts without needing developer assistance.

Showing the Selected Layout on the Request Page

To complete the user experience, Erik adds a read-only field on the report’s request page that displays which layout has been selected:

requestpage
{
    layout
    {
        area(content)
        {
            field(LayoutCtl; Layout.Description)
            {
                Caption = 'Selected Layout';
                ApplicationArea = All;
                Editable = false;
            }
        }
    }
}

This gives users clear feedback about which layout will be used before they hit Preview or Print.

Creating Word Layouts

Erik walks through creating a new Word layout from scratch:

  1. Go to the Edit Layouts action and create a new Word document layout
  2. Export the layout and open it in Microsoft Word
  3. Enable the Developer ribbon in Word (right-click the ribbon → Customize the Ribbon → check Developer)
  4. Open the XML Mapping Pane from the Developer ribbon
  5. Find the XML schema labeled “Dynamics NAV” (yes, it still says NAV rather than BC)
  6. Browse the available fields from the report’s dataset and insert them into the document
  7. Save the Word document
  8. Back in Business Central, import the layout file — this is a step users often forget, since saving the file locally doesn’t automatically update Business Central

Practical Use Cases

This technique solves a very common problem Erik has seen in the field: clients who have 25 copies of the same report object (like an invoice) simply because different users or customer groups need different layouts. With this approach:

  • You maintain a single report object with one dataset
  • All layout variations live as custom report layouts
  • Users can create and manage their own layouts without developer involvement
  • You could even extend this concept to automatically select layouts based on context (e.g., assigning a specific layout to a customer card)

Complete Report Source Code

Here’s the full report object with the dynamic layout selection built in:

report 50123 "Multi Report"
{
    UsageCategory = ReportsAndAnalysis;
    ApplicationArea = All;
    dataset
    {
        dataitem(Customer; Customer)
        {
            column(No; "No.") { }
            column(Name; Name) { }
            column(Address; Address) { }
            column(City; City) { }
            // ... all other customer columns ...
        }
    }
    requestpage
    {
        layout
        {
            area(content)
            {
                field(LayoutCtl; Layout.Description)
                {
                    Caption = 'Selected Layout';
                    ApplicationArea = All;
                    Editable = false;
                }
            }
        }
        actions
        {
            area(processing)
            {
            }
        }
    }
    trigger OnInitReport()
    var
        RLS: Record "Report Layout Selection";
    begin
        Layout.Setrange("Report ID", 50123);
        if page.RunModal(50123, Layout) = action::LookupOK then
            RLS.SetTempLayoutSelected(Layout.Code)
        else
            error('Please select a layout to continue!');
    end;

    var
        Layout: Record "Custom Report Layout";
}

Summary

With just a few lines of code, Erik demonstrates how to build a “100 in 1” report system in Business Central. The approach leverages the OnInitReport trigger combined with SetTempLayoutSelected to let users dynamically choose which layout to apply at runtime. This eliminates the need for duplicate report objects when the underlying dataset is the same, empowers end users to create and manage their own layouts, and keeps your codebase clean and maintainable. It’s a simple but powerful pattern that can dramatically reduce report maintenance overhead in real-world implementations.