Search code examples
dynamics-business-centraldynamics-al

Can you dynamically create a list page in Business Central using AL?


Is it possible to dynamically create a list page in Business Central using AL where you define the columns on page load?

Example is I have a data table defined where there are Fields 1 - 5:

table 50102 MyDataTable
{
    DataClassification = ToBeClassified;

    fields
    {
        field(1; "F1"; Text[150])
        {
            DataClassification = ToBeClassified;
        }
        field(2; "F2"; Text[150])
        {
            DataClassification = ToBeClassified;
        }

        field(3; "F3"; Text[150])
        {
            DataClassification = ToBeClassified;
        }

        field(4; "F4"; Text[150])
        {
            DataClassification = ToBeClassified;
        }

        field(5; "F5"; Text[150])
        {
            DataClassification = ToBeClassified;
        }
    }
}

This is intended to store data in different fields depending on an import type. This import has a mapping stored in another table which says that if we import an excel file of X type then column 1 goes to field F1, column 2 goes to field F3, column 3 goes to field F5. A different import type of Y will store values in different columns in the data table.

Problem is when we need to display the values in this data table according to the import type. If we're viewing the data I only want to see the columns associated with it.

examples: For type X I only want to show a list page with fields F1, F3, F5. For Y type I would like to show a list page with fields F1, F2, F4, F5

Is this possible in AL? Can you call out to a codeunit in the list page per field to determine if its to be shown?

In other words, is something like this possible?

page 50102 MyImportedDataList
{
ApplicationArea = All;
Caption = 'Import File';
PageType = List;
SourceTable = MyDataTable;
UsageCategory = Administration;
Editable = false;

layout
{
    area(Content)
    {
        repeater(Group)
        {
            field(Column1; rec.F1)
            {
                ApplicationArea = All;
                visible = myCodeunit.IsThisColumnVisible(Rec.F1); // <<---- IS THIS POSSIBLE
            }
            
            // Other columns omitted
        }
    }
}
}

Solution

  • You are on the right track however you cannot call a procedure in the expression of the Visible property.

    This will cause a compiler error:

    Procedure calls is not valid for client expressions
    

    However there is a workaround for this.

    First you must create a global variable and use it in the expression for the Visible property:

    field(Column1; rec.F1)
    {
        Visible = IsF1Visible;
    }
    
    ...
    
    var
        IsF1Visible: Boolean;
    

    Then you create a procedure to update the value of your new global variable:

    local procedure UpdateControls()
    begin
        IsF1Visible := MyCodeunit.IsThisColumnVisible(Rec.F1);
        ...
    end;
    

    Lastly you need to call the procedure at the right moments. There are two possibilities here:

    1. You already know which columns should be shown when opening the page
    2. You only know which columns should be shown after loading the first record or more

    Scenario 1

    You call the procedure in OnOpenPage:

    trigger OnOpenPage()
    begin
        UpdateControls();
    end;
    

    Because no data is loaded yet, you might need to supply some context before opening the page or use the filters on the page to determine which import type it is.

    Scenario 2

    You call the procedure in OnAfterGetRecord and OnAfterGetCurrRecord:

    trigger OnAfterGetRecord()
    begin
        UpdateControls();
    end;
    
    trigger OnAfterGetCurrRecord()
    begin
        UpdateControls();
    end;