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.
'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
'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.
'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;