+49 541 9493-0  Kontakt  

SNC Mobile

With SNC Mobile you are able to create your own forms within Business Central. This documentation should help you with building your first form and write the code for it.

Note
This document is for information purposes only. If used for other purposes, SIEVERS-SNC Computer & Software GmbH & Co. KG disclaims all warranties for defects in title and quality. SIEVERS-SNC Computer & Software GmbH & Co. KG disclaims all liability for direct and indirect damages - whether in contract or in law - arising out of or in connection with the use of this manual. This manual is subject to change without notice by SIEVERS-SNC Computer & Software GmbH & Co. KG without prior notice. The programs described may only be used or copied in accordance with the terms of the license. This document has been prepared for the support of end users, sales and service as well as developers and may be given to this group of persons without any changes. Copyright notice
Copyright © 2025 SIEVERS-SNC Computer & Software GmbH & Co. KG, a company of the SIEVERS-GROUP, Hans-Wunderlich Str.8, D-49078 Osnabrück, Germany. Microsoft, Microsoft Dynamics NAV and Business Central and Datev are registered trademarks. All rights not expressly granted are reserved. Published by SIEVERS-SNC Computer & Software GmbH & Co. KG.

1 Preparations

After you installed Mobile on Business Central, you have to adjust the dependencies in the app.json for Mobile.

    "dependencies": [{"id": "insert App-ID here","name": "SNC Mobile","publisher": "SIEVERS-GROUP","version": "versionnumber"}],

After that you can turn your attention to the SNCMobileMain.Page. This page is an example of a landing page and also serves as a container for Mobile to be displayed at all. You can find the page in the appendix in section SNC MobileMain.Page.al. It does not have to be changed. Of course, it can also be copied to create new forms.

2 Mobile Setup Wizard

For the initial basic setup, we recommend that you use the SNC Mobile Setup Wizard. You can find it in the search under SNC Mobile Setup Wizard.

For convenience reasons, we recommend linking the user to the Windows user name to avoid an additional login screen.

Afterwards, you can import previously exported masks, if available.

Finally, you can set in SNC Mobile Setup when history data should be deleted. History Data is all the data collected when a Mobile form communicates with Business Central. You can view the data in the SNc Mobile History report.

3 Creation of the first Form

To create a form, open the SNC Mobile Forms page and create a new record via New. Name it in the Code field and fill in a description. It is also important that you enter the Page Name of the above-mentioned landing page in the corresponding field. This is only necessary for the first form, so that it is clear which form should be loaded initially as soon as the user opens the specific landing page in Business Central.

Page Name

Afterwards the Configurator can be opened.

Page Name

The Configurator is now still quite white and empty. Therefore it should be filled. Elements can be added via + Add Control. Create these three elements as an example:

After this save the form and return to the form card.

Attention

When making changes in the form, the Configurator must be saved before exiting! If you exit the Configurator without saving, the changes will be lost.

The following setting options are available here:

In the lower area you will find the sections Layout, SNC Mobile Controls, Columns and Rows.

In Layout you can define the number of columns and rows, the column and row gaps and the maximum width and height of the mask. The fields of the columns and rows and the gaps are filled automatically. SNC Mobile Controls shows the mask created in the configurator in the form of the fields with their contents and properties. In the Columns and Rows areas, the elements created in the configurator are again displayed row by row and column by column.

When you are finished with the settings of the mask, you have to release it.

Note

During the release, the system checks whether the configuration created matches the settings of the record.

To view the created form, you can open the SNC Mobile page. You will notice that the buttons have no function yet.

3.1 Structure of the Forms CodeUnit

To breathe life into the exit button, a new CodeUnit must be created in VSCode. The CodeUnit of a form must always contain five specific elements to be functional:

Note

You can find the complete CodeUnit in section SNC.MainForm.Codeunit.al

This interface is for the communication with the framework:

    Interface: Codeunit "SNC Mobile Interface Add-In";

With the following function the form can be identified. Instead of MAIN at the label, enter the name which you gave to the form during creation:

local procedure GetFormCode(): Code[20]
var
    FormCode: Label 'MAIN';
begin
    exit(FormCode);
end;

The following two code blocks are events that can be used to initialize or clear something away. They are similar to an OnOpenPageTrigger or OnClosePageTrigger.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"SNC Mobile Interface Add-In", 'OnAfterGetForm', '', false, false)]
local procedure OnAfterGetForm(var Sender: Codeunit "SNC Mobile Interface Add-In")
    begin
        Interface := Sender;
        if not Interface.CheckHandleEvent(GetFormCode()) then
            exit;
    end;


[EventSubscriber(ObjectType::Codeunit, Codeunit::"SNC Mobile Interface Add-In", 'OnQueryCloseForm', '', false, false)]
local procedure OnQueryCloseForm(var Sender: Codeunit "SNC Mobile Interface Add-In"; CloseRaisedByCloseNavPage: Boolean; var DoNotClose: Boolean)
    begin
        Interface := Sender;
        if not Interface.CheckHandleEvent(GetFormCode()) then
            exit;
        DoNotClose := not CloseRaisedByCloseNavPage;
    end;

The following event is the most important for the function of the forms. It is always used when anything in the form changes. This can be, for example, the triggering of a button or the confirmation of an entry in a field by the Return key.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"SNC Mobile Interface Add-In", 'OnControlEvent', '', false, false)]
local procedure ControlEventSub(var Sender: Codeunit "SNC Mobile Interface Add-In"; var Handled: Boolean)
var
    begin
        Interface := Sender;
        if Handled or not Interface.CheckHandleEvent(GetFormCode()) then
            exit;
    Handled := true;

    end;

The most important part of this code block is the Handled Pattern:

    Interface := Sender;
    if Handled or not Interface.CheckHandleEvent(GetFormCode()) then
        exit;
    Handled := true;

This checks two possibilities:

This Handled pattern must be part of the CodeUnit.

If the event is not yet handled, Handled:= true; can be set. As a result, a case construct is usually built to handle the user’s actions.

The following explains how to build a case construct for the exit button.

The first line is used to analyze which action was performed:

    case UpperCase(Interface.GetActiveControlAction()) of

To be able to execute the exit action now you need an action name (in this case LOGOUT), the action itself and of course an else case:

    'LOGOUT':
        Interface.CloseNavPage();
    else
            Handled := false;
    end;

Now the finished code can be deployed as follows.

    case UpperCase(Interface.GetActiveControlAction()) of
        'LOGOUT':
            Interface.CloseNavPage();
        else
            Handled := false;
    end;

Next, the LOGOUT action you just created must be linked to the corresponding button in the form. To do this, open the SNC Mobile Forms page again and the form you have just created.
The Configurator cannot be opened yet, because the form is in state release. Reset the status using Reset Status in order to be able to edit the form again.
Now open the Configurator, select the EXIT button and enter the name you just gave to the case in the Action Code field at Control Basics on the right side. In this case it was LOGOUT.

When the button is clicked, the LOGOUT action is passed to the code, which recognizes it and then executes the corresponding case - in this case the page closes.

Ideally, the button should work now when you open the form via SNC Mobile.

3.2 Linking Forms

3.2.1 Creation of a new form and adjustments in the parent form

Create a new form as described in Creation of the first Form via Configuration.

In this example there is one input (scan) and one output

Make sure that input fields are editable. This setting can be found under Control Settings.

First of all, the exit button should get a function. Since this is a sub-form, the exit button should not only close the form, but also open the parent form.

For this purpose, the button must be assigned an Action Code and an Action Parameter. In this case the action code is OPENFORM. For Action Parameter enter the name of the parent form. In this case it is MAIN.

Save the form, release it and close it.

Now open the parent form. If you have created it as explained in section Creation of the first Form, the form contains the SUBFORM1 button. Select this button and assign the action code OPENFORM here as well. The name of the sub-form is entered in the Action Parameter field. In this example it is SUB1.

At this point the forms are finished. The next step is to implement the code for the SUBFORM1 button in the MAIN form. This is the button that is used to switch from the parent form to the sub-form.

3.2.2 Implementation in the CodeUnit

Ideally, a case construct already exists in the code unit of the MAIN form in the OnControlEvent. If this is not the case, you will find the corresponding explanations in section Creation of the first Form.

Now add a new case to this case construct. When you created the new form, you used OPENFORM as action code. For the sake of clarity, we recommend using the action code for the case name as well.

    'OPENFORM':
            Interface.OpenNewForm(Interface.GetActiveControlActionParameter());

With Interface.OpenNewForm a new form is opened. In the brackets, Interface.GetActiveControlActionParameter() queries the content of the Action Parameter field in the button settings of the form. Since the SUB1 form was entered there earlier, the corresponding form is also opened.

For the SUB1 form, a CodeUnit must now also be created. As a basic structure you can simply copy the MAIN-CodeUnit. Please note that you not only have to adapt the ID and the name, but also the label at GetFormCode. Also delete the LOGOUT case in the case construct in the OnControlEvent.

Now the case construct should still have the following:

    case UpperCase(Interface.GetActiveControlAction()) of
        'OPENFORM':
            Interface.OpenNewForm(Interface.GetActiveControlActionParameter());
        else
            Handled := false;
    end;

The button SubForm1 of the MAIN form and the EXIT button of the sub form should work now. The linking of the two forms is now complete.

4 Query information from Business Central

The explanations in this chapter are based on the code and form framework of Section 3.

You have created the SubForm1 form with two text fields: Scan and Output. You now want to use these two text fields to create a customer query. A customer number will be entered in the scan field and the customer name will be printed in the output.

In order to be able to read the scan field correctly, an action code must be stored in the form configuration.

Once you have done that, you can move on to the code in the CodeUnit of the sub-form.

First create a new variable for the customer in the OnControlEvent.

    var
        Customer: Record Customer;

In the case construct of the OnControlEvent you create a new case SCAN for the action of the textfield (which is triggered by the return-key).

    case UpperCase(Interface.GetActiveControlAction()) of
        'SCAN':
            begin
                Customer.get(Interface.GetValue(Interface.GetActiveControlName()));
            end
        'OPENFORM':
            Interface.OpenNewForm(Interface.GetActiveControlActionParameter());
        else
            Handled := false;
    end;

With Interface.GetActiveControlName() it is recognized which field is currently selected. From this the entered value is taken with Interface.GetValue().

Subsequently, value must be used to enter the correct customer name into the output field.

    'SCAN':
            begin
                Customer.get(Interface.GetValue(Interface.GetActiveControlName()));
                Interface.SetValue('OUTPUT', Customer.Name);
            end

With Interface.SetValue() the Customer.Name is now being written into the output field.

The implementation of the code is now complete.

5 Output acoustic signals

With Mobile you are able to output sounds like beeps. This can be helpful, for example, when an error occurs or a form has been completed successfully. There is an event in SNC Mobile for this function. You call it with:

    Interface.Beep('Base64Text');

Instead of Base64Text, a Base64 string corresponding to the tone is inserted. You can generate new Base64 texts for example with the website dopiaza.org.

6 Nutzung von HTML in Masken

In mask fields you have the possibility to include any HTML code.
Example of a label:

Variable:

    var
    Teststring: Label '<div style="border:1px solid black;width:100%;height:100%;display: flex;justify-content: center;align-items: center;">Text hier<br>einfügen</div>';

Embedding: (OUTPUT is the name of the form element)

    Interface.SetValue('OUTPUT', Teststring);
This is how a label looks like after using the teststring
Note

The inclusion of HTML code is not possible with selectors and text boxes.

7 Design forms clearer

Forms should be designed as clearly as possible. SNC Mobile offers some possibilities for this.

To avoid placing elements directly below each other, a spacer can be inserted between them. This is an empty field.

Also, there are styling settings for each field that you can use to separate them from each other:

8 Embedding a software keyboard

To include software keyboards in masks, the particular keyboards must first be imported as forms. There are a number of .json files for this purpose. If you do not have these files, please contact us.

You can import these files directly into SNC Mobile Forms via the form import. After that open the form in which you want to insert the keyboard. Under SNC Mobile Controls, find the field for which you want to use the keyboard. Go via Manage to Details.

Here you have to activate the keyboard in the Keyboard area and enter the keyboard form code.

If the keyboard does not appear in the selection menu, it may not be marked as such. To do this, check in the corresponding form card whether the check mark is Keyboard is set.

9 Notes on handling Mobile

  1. If you want to edit an already released shape again, you have to reset the status of the form first.

  1. Remember to save the form after editing it in the Configurator.

  2. For the Page of a new form, you can always use the SNCMobileMain.Page.al template.

10 Appendix

10.1 SNC MobileMain.Page.al

    page 50100 "SNC Mobile Main"
{
Caption = 'SNC Mobile';
UsageCategory = Tasks;
ApplicationArea = All;
PageType = Card;

layout
{
    area(content)
    {
        usercontrol("ControlAddIn"; SNCMobileAddIn)
        {
            ApplicationArea = All;
            trigger ControlReady()
            begin
                if not Initialized then begin
                    BindSubscription(SNCMobileJScript);
                    Initialized := true;
                    SNCMobileJScript.Initialize(CurrPage.ControlAddIn, SavedVariantValue);
                end;

                SNCMobileJScript.RequestUI(CurrPage.ObjectId(false));
            end;

            trigger ControlEvent(JObject: JsonObject)
            begin
                SNCMobileJScript.ControlEvent(CurrPage.ObjectId(false), JObject, SavedVariantValue);
                CurrPage.ControlAddIn.removeHold();
            end;

            trigger KeyboardEvent(JObject: JsonObject)
            begin
                SNCMobileJScript.KeyboardEvent(JObject);
            end;

            trigger NavPageCloseCalled()
            begin
                CloseRaisedByCloseNavPage := true;
                CurrPage.Close();
            end;
        }
    }
}

trigger OnClosePage()
begin
    if Initialized then begin
        Initialized := false;
        UnbindSubscription(SNCMobileJScript);
    end;
end;

trigger OnQueryClosePage(CloseAction: Action): Boolean
var
    DoNotClose: Boolean;
begin
    SNCMobileJScript.RequestClose(CurrPage.OBJECTID(FALSE), SavedVariantValue, CloseRaisedByCloseNavPage, DoNotClose);
    exit(not DoNotClose);
end;

procedure SetMobileUser(MobileUser: Code[20])
begin
    SNCMobileJScript.SetMobileUserID(MobileUser);
end;

procedure SetVariantValue(VariantValue: Variant)
begin
    SavedVariantValue := VariantValue;
    SNCMobileJScript.SetVariantValue(SavedVariantValue);
end;

procedure GetVariantValue(var VariantValue: Variant)
begin
    SNCMobileJScript.GetVariantValue(VariantValue);
    if VariantValue.IsRecord or VariantValue.IsRecordRef then
        Error(RecRefError);
end;

procedure GetVariantValue(var TextValue: Text)
var
    VariantValue: Variant;
begin
    SNCMobileJScript.GetVariantValue(VariantValue);
    TextValue := VariantValue;
end;

procedure GetVariantValue(var TextValue: Code[2048])
var
    VariantValue: Variant;
begin
    SNCMobileJScript.GetVariantValue(VariantValue);
    TextValue := VariantValue;
end;

procedure GetVariantValue(var IntegerValue: Integer)
var
    VariantValue: Variant;
begin
    SNCMobileJScript.GetVariantValue(VariantValue);
    IntegerValue := VariantValue;
end;

procedure GetVariantValue(var DecimalValue: Decimal)
var
    VariantValue: Variant;
begin
    SNCMobileJScript.GetVariantValue(VariantValue);
    DecimalValue := VariantValue;
end;

procedure GetVariantValue(var BooleanValue: Boolean)
var
    VariantValue: Variant;
begin
    SNCMobileJScript.GetVariantValue(VariantValue);
    BooleanValue := VariantValue;
end;

procedure GetVariantValue(var JsonObj: JsonObject)
var
    VariantValue: Variant;
begin
    SNCMobileJScript.GetVariantValue(VariantValue);
    JsonObj := VariantValue;
end;

procedure GetVariantValue(var RecRef: RecordRef)
var
    RecVariant: Variant;
begin
    SNCMobileJScript.GetVariantValue(RecVariant);
    RecRef.GetTable(RecVariant);
end;

var
    SNCMobileJScript: Codeunit "SNC Mobile JScript";
    Initialized: Boolean;
    CloseRaisedByCloseNavPage: Boolean;
    SavedVariantValue: Variant;
    RecRefError: Label 'Use RecordRef instead of Variant to get Table Data.';
}

10.2 SNCMainForm.Codeunit.al

    codeunit 50100 "SNCMainForm"
{


[EventSubscriber(ObjectType::Codeunit, Codeunit::"SNC Mobile Interface Add-In", 'OnControlEvent', '', false, false)]
local procedure ControlEventSub(var Sender: Codeunit "SNC Mobile Interface Add-In"; var Handled: Boolean)
var
begin
    Interface := Sender;
    if Handled or not Interface.CheckHandleEvent(GetFormCode()) then
        exit;
    Handled := true;

    case UpperCase(Interface.GetActiveControlAction()) of
        'LOGOUT':
            Interface.CloseNavPage();
        'OPENFORM':
            Interface.OpenNewForm(Interface.GetActiveControlActionParameter());
        else
            Handled := false;
    end;

end;


[EventSubscriber(ObjectType::Codeunit, Codeunit::"SNC Mobile Interface Add-In", 'OnAfterGetForm', '', false, false)]
local procedure OnAfterGetForm(var Sender: Codeunit "SNC Mobile Interface Add-In")
begin
    Interface := Sender;
    if not Interface.CheckHandleEvent(GetFormCode()) then
        exit;
end;

[EventSubscriber(ObjectType::Codeunit, Codeunit::"SNC Mobile Interface Add-In", 'OnQueryCloseForm', '', false, false)]
local procedure OnQueryCloseForm(var Sender: Codeunit "SNC Mobile Interface Add-In"; CloseRaisedByCloseNavPage: Boolean; var DoNotClose: Boolean)
begin
    Interface := Sender;
    if not Interface.CheckHandleEvent(GetFormCode()) then
        exit;
    DoNotClose := not CloseRaisedByCloseNavPage;
end;


local procedure GetFormCode(): Code[20]
var
    FormCode: Label 'MAIN';
begin
    exit(FormCode);
end;

var
    Interface: Codeunit "SNC Mobile Interface Add-In";
}