Skip to content

Input Line Event

Business Portals can trigger an event based on input in a line on the frontend. This input is sent to Business Central, where it can be processed by a custom codeunit to recalculate values or return a specific result.

This section provides an example of how to implement a custom codeunit that is triggered by an event based on user input.

Code Example

In this example, we will use the Sales Order Line table in a scenario where the user can input a quantity for the items listed in a line. The input will update the item price by multiplying the quantity with the unit price.

The user input triggers an event by sending the value to Business Central, where it is processed in a Business Central codeunit.

AL
'INPUTLINE':
    begin
        LocalEventXmlElement := XmlElement.Create('EVENT');
        LocalRootXmlElement.Add(LocalEventXmlElement);
        LocalRootXmlElement.SetAttribute('EVENTTYPE', ParamRecordSIMDPSOL."Sub Function Event");
        LocalRootXmlElement.SetAttribute('EVENTVALUE', LocalEventValueText);
        LocalRootXmlElement.SetAttribute('EVENTMESSAGE', 'All lines with the same quantity will be selected.');
        LocalRootXmlElement.SetAttribute('EVENTMESSAGETYPE', 'default');
        LocalRootXmlElement.SetAttribute('EVENTMESSAGEMOBILE', '');
        LocalRootXmlElement.SetAttribute('EVENTMESSAGEMOBILETYPE', 'default');

        if Evaluate(LocalRecordId, LocalEventValueText, 9) then
            if LocalRecordRef.Get(LocalRecordId) then begin
                LocalLineRecordSIMDPSOL.Reset();
                LocalLineRecordSIMDPSOL.SetRange("Entry No.", ParamRecordSIMDPSOL."Entry No.");
                LocalLineRecordSIMDPSOL.SetRange("Sub Entry No.", ParamRecordSIMDPSOL."Sub Entry No.");
                LocalLineRecordSIMDPSOL.SetRange("Dataset Code", ParamRecordSIMDPSOL."Dataset Code");
                LocalLineRecordSIMDPSOL.SetRange("Dataset Table Code", ParamRecordSIMDPSOL."Dataset Table Code");
                LocalLineRecordSIMDPSOL.SetRange("Dataset Table Type", ParamRecordSIMDPSOL."Dataset Table Type"::Line);
                LocalLineRecordSIMDPSOL.SetRange("Dataset Table Record", LocalRecordId);

                // This will get the value of what is entered in the frontend,
                if LocalLineRecordSIMDPSOL.FindSet() then
                    LocalInputText := GlobalCodeunitSIMDPSOrderFunctionLibrary.GetDPSOrderLineInputFieldByCode(LocalLineRecordSIMDPSOL, 'QUANTITY');

                // Filter at the exact line which triggers the event, and get the value of other fields for calculation, then return the value to frontend. It is just an example based on Quantity field, it can be any other fields and any calculation based on the requirement. It is recommended to directly get the line which triggers the event and return the value for that line only, then do the calculation on client side, if there are performance concern when there are lots of lines with the same quantity.
                LocalRecordRef.SetTable(LocalRecordSalesLine);
                Local2RecordSalesLine.SetRange("Document Type", LocalRecordSalesLine."Document Type");
                Local2RecordSalesLine.SetRange("Document No.", LocalRecordSalesLine."Document No.");
                Local2RecordSalesLine.SetRange("Line No.", LocalRecordSalesLine."Line No.");
                Local2RecordSalesLine.SetRange(Quantity, LocalRecordSalesLine.Quantity);
                if Local2RecordSalesLine.FindFirst() then begin
                    // This code block will return the input value to the frontend.
                    LocalInfoXmlElement := XmlElement.Create('INFO');
                    LocalEventXmlElement.Add(LocalInfoXmlElement);
                    LocalInfoXmlElement.SetAttribute('VALUE', Format(Local2RecordSalesLine.RecordId, 0, 9));

                    LocalInputXmlElement := XmlElement.Create('INPUT');
                    LocalInfoXmlElement.Add(LocalInputXmlElement);
                    LocalInputXmlElement.SetAttribute('NAME', 'QUANTITY');
                    LocalInputXmlElement.SetAttribute('VALUE', LocalInputText);

                    // This code block will return other field values, based on the input value, to the frontend for calculation. In this example, it returns Unit Price and does a multiplication on backend, then return the result to frontend, but it can be any other fields and any calculation based on the requirement.
                    LocalInfoXmlElement := XmlElement.Create('INFO');
                    LocalEventXmlElement.Add(LocalInfoXmlElement);
                    LocalInfoXmlElement.SetAttribute('VALUE', Format(Local2RecordSalesLine.RecordId, 0, 9));

                    LocalInputXmlElement := XmlElement.Create('INPUT');
                    LocalInfoXmlElement.Add(LocalInputXmlElement);
                    Evaluate(LocalMultiplierDecimal, LocalInputText);

                    LocalSumDecimal := LocalMultiplierDecimal * Local2RecordSalesLine."Unit Price";

                    LocalInputXmlElement.SetAttribute('NAME', 'PRICE');
                    LocalInputXmlElement.SetAttribute('VALUE', Format(LocalSumDecimal, 0, 9));
                end;
            end;
    end;

Code Example 2

With a similar scenario as the first Code Example, this code example will show how to update all of the lines rather than only the selected line

AL
 'INPUTLINE':
    begin
        LocalEventXmlElement := XmlElement.Create('EVENT');
        LocalRootXmlElement.Add(LocalEventXmlElement);
        LocalRootXmlElement.SetAttribute('EVENTTYPE', ParamRecordSIMDPSOL."Sub Function Event");
        LocalRootXmlElement.SetAttribute('EVENTVALUE', LocalEventValueText);
        LocalRootXmlElement.SetAttribute('EVENTMESSAGE', 'Alle Zeilen mit der gleichen Anzahl wurden abgewählt.');
        LocalRootXmlElement.SetAttribute('EVENTMESSAGETYPE', 'default');
        LocalRootXmlElement.SetAttribute('EVENTMESSAGEMOBILE', '');
        LocalRootXmlElement.SetAttribute('EVENTMESSAGEMOBILETYPE', 'default');

        if Evaluate(LocalRecordId, LocalEventValueText, 9) then
            if LocalRecordRef.Get(LocalRecordId) then begin
                LocalLineRecordSIMDPSOL.Reset();
                LocalLineRecordSIMDPSOL.SetRange("Entry No.", ParamRecordSIMDPSOL."Entry No.");
                LocalLineRecordSIMDPSOL.SetRange("Sub Entry No.", ParamRecordSIMDPSOL."Sub Entry No.");
                LocalLineRecordSIMDPSOL.SetRange("Dataset Code", ParamRecordSIMDPSOL."Dataset Code");
                LocalLineRecordSIMDPSOL.SetRange("Dataset Table Code", ParamRecordSIMDPSOL."Dataset Table Code");
                LocalLineRecordSIMDPSOL.SetRange("Dataset Table Type", ParamRecordSIMDPSOL."Dataset Table Type"::Line);
                LocalLineRecordSIMDPSOL.SetRange("Dataset Table Record", LocalRecordId);

                // This will get the value of what is entered in the frontend,
                if LocalLineRecordSIMDPSOL.FindSet() then
                    LocalInputText := GlobalCodeunitSIMDPSOrderFunctionLibrary.GetDPSOrderLineInputFieldByCode(LocalLineRecordSIMDPSOL, 'QUANTITY');

                // To loop through all lines with the same quantity, the code can be like below, but it may have performance issue when there are lots of lines, so it is better to directly get the line which triggers the event and return the value for that line only, then do the calculation on client side.

                LocalRecordRef.SetTable(LocalRecordSalesLine);
                Local2RecordSalesLine.SetRange("Document Type", LocalRecordSalesLine."Document Type");
                Local2RecordSalesLine.SetRange("Document No.", LocalRecordSalesLine."Document No.");
                Local2RecordSalesLine.SetRange(Quantity, LocalRecordSalesLine.Quantity);
                if Local2RecordSalesLine.FindSet() then
                    repeat
                        LocalInfoXmlElement := XmlElement.Create('INFO');
                        LocalEventXmlElement.Add(LocalInfoXmlElement);
                        LocalInfoXmlElement.SetAttribute('VALUE', Format(Local2RecordSalesLine.RecordId, 0, 9));

                        LocalInputXmlElement := XmlElement.Create('INPUT');
                        LocalInfoXmlElement.Add(LocalInputXmlElement);
                        LocalInputXmlElement.SetAttribute('NAME', 'QUANTITY');
                        LocalInputXmlElement.SetAttribute('VALUE', LocalInputText);

                        LocalInputXmlElement := XmlElement.Create('INPUT');
                        LocalInfoXmlElement.Add(LocalInputXmlElement);
                        Evaluate(LocalMultiplierDecimal, LocalInputText);

                        LocalSumDecimal := LocalMultiplierDecimal * Local2RecordSalesLine."Unit Price";

                        LocalInputXmlElement.SetAttribute('NAME', 'PRICE');
                        LocalInputXmlElement.SetAttribute('VALUE', Format(LocalSumDecimal, 0, 9));

                    until Local2RecordSalesLine.Next() = 0;
            end
    end;

Code Example 3

With a similar scenario as the first Code Example, this code example will show how to update the lines of the selected line with more fields, as well as blocking an update when a specific field is changed.

In this example an addition of two more fields are inserted namely BRUTTO and NETTO. This field will be using a fake static number, because the standard Sales Order Line table does not have these values/fields in the database. This fields can be replaced by anyhting else.

AL
 'INPUTLINE':
    begin
    LocalEventXmlElement := XmlElement.Create('EVENT');
    LocalRootXmlElement.Add(LocalEventXmlElement);
    LocalRootXmlElement.SetAttribute('EVENTTYPE', ParamRecordSIMDPSOL."Sub Function Event");
    LocalRootXmlElement.SetAttribute('EVENTVALUE', LocalEventValueText);
    LocalRootXmlElement.SetAttribute('EVENTMESSAGE', 'Alle Zeilen mit der gleichen Anzahl wurden abgewählt.');
    LocalRootXmlElement.SetAttribute('EVENTMESSAGETYPE', 'default');
    LocalRootXmlElement.SetAttribute('EVENTMESSAGEMOBILE', '');
    LocalRootXmlElement.SetAttribute('EVENTMESSAGEMOBILETYPE', 'default');

    if Evaluate(LocalRecordId, LocalEventValueText, 9) then
        if LocalRecordRef.Get(LocalRecordId) then begin
            LocalLineRecordSIMDPSOL.Reset();
            LocalLineRecordSIMDPSOL.SetRange("Entry No.", ParamRecordSIMDPSOL."Entry No.");
            LocalLineRecordSIMDPSOL.SetRange("Sub Entry No.", ParamRecordSIMDPSOL."Sub Entry No.");
            LocalLineRecordSIMDPSOL.SetRange("Dataset Code", ParamRecordSIMDPSOL."Dataset Code");
            LocalLineRecordSIMDPSOL.SetRange("Dataset Table Code", ParamRecordSIMDPSOL."Dataset Table Code");
            LocalLineRecordSIMDPSOL.SetRange("Dataset Table Type", ParamRecordSIMDPSOL."Dataset Table Type"::Line);
            LocalLineRecordSIMDPSOL.SetRange("Dataset Table Record", LocalRecordId);

            // This will get the value of what is entered in the frontend,
            if LocalLineRecordSIMDPSOL.FindSet() then
                LocalQuantityInputText := GlobalCodeunitSIMDPSOrderFunctionLibrary.GetDPSOrderLineInputFieldByCode(LocalLineRecordSIMDPSOL, 'QUANTITY');
            if LocalLineRecordSIMDPSOL.FindSet() then
                LocalBruttoInputText := GlobalCodeunitSIMDPSOrderFunctionLibrary.GetDPSOrderLineInputFieldByCode(LocalLineRecordSIMDPSOL, 'BRUTTO');
            if LocalLineRecordSIMDPSOL.FindSet() then
                LocalNettoInputText := GlobalCodeunitSIMDPSOrderFunctionLibrary.GetDPSOrderLineInputFieldByCode(LocalLineRecordSIMDPSOL, 'NETTO');
            if LocalLineRecordSIMDPSOL.FindSet() then
                LocalPriceInputText := GlobalCodeunitSIMDPSOrderFunctionLibrary.GetDPSOrderLineInputFieldByCode(LocalLineRecordSIMDPSOL, 'PRICE');

            // Safeguard for empty input, if the input is empty, it will be treated as 0 in calculation. This is the case when it is a number input, for text input, it can be treated as empty string and no need to convert to 0.
            if LocalQuantityInputText = '' then
                LocalQuantityInputText := '0';
            if LocalBruttoInputText = '' then
                LocalBruttoInputText := '0';
            if LocalNettoInputText = '' then
                LocalNettoInputText := '0';
            if LocalPriceInputText = '' then
                LocalPriceInputText := '0';

            // Filter at the exact line which triggers the event, and get the value of other fields for calculation, then return the value to frontend. It is just an example based on Quantity field, it can be any other fields and any calculation based on the requirement. It is recommended to directly get the line which triggers the event and return the value for that line only, then do the calculation on client side, if there are performance concern when there are lots of lines with the same quantity.
            LocalRecordRef.SetTable(LocalRecordSalesLine);
            Local2RecordSalesLine.SetRange("Document Type", LocalRecordSalesLine."Document Type");
            Local2RecordSalesLine.SetRange("Document No.", LocalRecordSalesLine."Document No.");
            Local2RecordSalesLine.SetRange("Line No.", LocalRecordSalesLine."Line No.");
            Local2RecordSalesLine.SetRange(Quantity, LocalRecordSalesLine.Quantity);
            if Local2RecordSalesLine.FindFirst() then begin
                // This code block will return the input value to the frontend.
                LocalInfoXmlElement := XmlElement.Create('INFO');
                LocalEventXmlElement.Add(LocalInfoXmlElement);
                LocalInfoXmlElement.SetAttribute('VALUE', Format(Local2RecordSalesLine.RecordId, 0, 9));

                LocalInputXmlElement := XmlElement.Create('INPUT');
                LocalInfoXmlElement.Add(LocalInputXmlElement);
                LocalInputXmlElement.SetAttribute('NAME', 'QUANTITY');
                LocalInputXmlElement.SetAttribute('VALUE', LocalQuantityInputText);

                // Evaluate the input value, and transfer it to the local variables.
                Evaluate(LocalMultiplierDecimal, LocalQuantityInputText);
                Evaluate(LocalBruttoDecimal, LocalBruttoInputText);
                Evaluate(LocalNettoDecimal, LocalNettoInputText);
                Evaluate(LocalPriceDecimal, LocalPriceInputText);

                //PRICE
                // This code block will return other field values, based on the input value, to the frontend for calculation. In this example, it returns Unit Price and does a multiplication on backend, then return the result to frontend, but it can be any other fields and any calculation based on the requirement.
                LocalInfoXmlElement := XmlElement.Create('INFO');
                LocalEventXmlElement.Add(LocalInfoXmlElement);
                LocalInfoXmlElement.SetAttribute('VALUE', Format(Local2RecordSalesLine.RecordId, 0, 9));

                LocalInputXmlElement := XmlElement.Create('INPUT');
                LocalInfoXmlElement.Add(LocalInputXmlElement);

                LocalSumDecimal := LocalMultiplierDecimal * Local2RecordSalesLine."Unit Price";

                if LocalPriceDecimal <> LocalSumDecimal then
                    LocalQuantityChangeBoolean := true;

                LocalInputXmlElement.SetAttribute('NAME', 'PRICE');
                LocalInputXmlElement.SetAttribute('VALUE', Format(LocalSumDecimal, 0, 9));

                // Check if QUANTITY field is changed or other fields are not initialized, then return the calculated BRUTTO and NETTO value to frontend, otherwise just return the input value to frontend without calculation
                if LocalQuantityChangeBoolean or (LocalBruttoDecimal = 0) or (LocalNettoDecimal = 0) then begin
                    //BRUTTO
                    // This code block will return the input value to the frontend.
                    LocalInfoXmlElement := XmlElement.Create('INFO');
                    LocalEventXmlElement.Add(LocalInfoXmlElement);
                    LocalInfoXmlElement.SetAttribute('VALUE', Format(Local2RecordSalesLine.RecordId, 0, 9));

                    LocalInputXmlElement := XmlElement.Create('INPUT');
                    LocalInfoXmlElement.Add(LocalInputXmlElement);

                    // The calculation logic is just for example, it can be any calculation based on the requirement.
                    // This calculates the multiplier value based on the input QUANTITY, then multiply with a value (10 in this example) to get the BRUTTO value, if the input QUANTITY is changed or the BRUTTO value is not initialized, otherwise just return the input BRUTTO value to frontend without calculation.
                    LocalSumDecimal := LocalMultiplierDecimal * 10;
                    if not LocalQuantityChangeBoolean then
                        if (LocalBruttoDecimal <> LocalSumDecimal) and (LocalBruttoDecimal <> 0) then
                            LocalSumDecimal := LocalBruttoDecimal;

                    LocalInputXmlElement.SetAttribute('NAME', 'BRUTTO');
                    LocalInputXmlElement.SetAttribute('VALUE', Format(LocalSumDecimal, 0, 9));

                    //NETTO
                    // This code block will return the input value to the frontend.
                    LocalInfoXmlElement := XmlElement.Create('INFO');
                    LocalEventXmlElement.Add(LocalInfoXmlElement);
                    LocalInfoXmlElement.SetAttribute('VALUE', Format(Local2RecordSalesLine.RecordId, 0, 9));

                    LocalInputXmlElement := XmlElement.Create('INPUT');
                    LocalInfoXmlElement.Add(LocalInputXmlElement);

                    // The calculation logic is just for example, it can be any calculation based on the requirement.
                    // This calculates the multiplier value based on the input QUANTITY, then multiply with a value (10 in this example) to get the BRUTTO value, if the input QUANTITY is changed or the BRUTTO value is not initialized, otherwise just return the input BRUTTO value to frontend without calculation.
                    LocalSumDecimal := LocalMultiplierDecimal * 5;

                    if not LocalQuantityChangeBoolean then
                        if (LocalNettoDecimal <> LocalSumDecimal) and (LocalNettoDecimal <> 0) then
                            LocalSumDecimal := LocalNettoDecimal;

                    LocalInputXmlElement.SetAttribute('NAME', 'NETTO');
                    LocalInputXmlElement.SetAttribute('VALUE', Format(LocalSumDecimal, 0, 9));
                end;
            end;
        end;
    end;