Hexagon Geospatial
MENU

M.App Enterprise Tutorials

Not sure on how to get started or looking for a workflow to get M.App Enterprise up and running. Tutorials provide step by instruction on some of the most common configurations and workflows to get M.App Enterprise configured up and running quickly.
Showing results for 
Search instead for 
Do you mean 

How to setup a Mobile App - Part 2

by sturcato on ‎11-05-2018 08:09 AM - edited on ‎04-16-2019 09:03 AM by sclow (2,333 Views)

In this tutorial we are going to extend the first article published here. We will start from the same data and shell and we will extend the configuration step by step.

 

The present article is divided in incremental labs. The material attached to this post is organized in the following way:

  1. Main folder is the current configuration of your shell. The workflow to update the shell configuration is:
    1. You will be working on the xaml files in this folder
    2. you create a zip file containing the modified xaml files 
    3. you upload the zip into the existing shell configuration in StudioCapture.PNG
  2. You have a subfolder for each Lab. In this folder you have:
    • the xaml files containing the result of the Lab (what is described in the Lab's paragraph below)
    • eventually a templates folder if you have to copy an existing configuration (it is described in the Lab's paragraph) 
    • eventually a script to update the data model (if described in the Lab's paragraph)

In the description below we assume you are working with a Postgresql database. You will find anyway the same scripts for Oracle or SqlServer databases.

 

 

Lab 1: Adding a Map

 

The goal of this first lab is to add a Map in your mobile App configuration. The Map will contain just the native Map available on your mobile device.

 

1.      Copy NativeMap.xaml from templates folder

2.      Shell.xaml ->  Add to MasterDetail.Views:

<Navigation Id="MapNavigation">

<NativeMap Id="NativeMap" Title="Map" Center="40.6239644;-74.00624" View="NativeMap" ZoomLevel="14" MapType="Roads"/>

</Navigation>

3.      Menu.xaml ->

a.      Add to Menu:

<MenuItem Target="MapNavigation" Title="Map" Icon="Map" Type="Toolbar"/>

b.      Add to Logout item

Type="Toolbar"

4.      Test App (logout and login again)

 

Lab 2a: Adding spatial information to Locations

 

The goal of this lab is to add a geometry field to our Locations table and to be able to capture this geometry within the mobile App.

 

1.      PostgreSql2.sql -> add geometry field

2.      Shell.xaml -> Add to Entity Id="Locations":

<Field Name="geometry" Type="Geometry" />

3.      NativeMap.xaml -> add to NativeMap.Layers:

<MarkerVectorLayer Entity="Locations" Icon="Map.Pin.png" ZIndex="3" MinimumZoomLevel="13" MaximumZoomLevel="22">

</MarkerVectorLayer>

4.      LocationForm.xaml -> add to Form:

<Geometry Name="geometry" Title="Geometry"> 

<GeometryFieldAction Target="NativeMap" Capture="True">

            <Parameter Name="ZoomLevel" Value="19" />

        </GeometryFieldAction>

</Geometry>

5.      Test App

 

Lab 2b: Adding tools to the Map

 

In this lab we are adding some new tools to interact with the map and get info about the selected object on the map (FeatureInfo with included details and actions to edit the object and to navigate to the object using the native mobile navigator App).

 

1.      NativeMap.xaml ->

a.      Add to NativeMap.ShellActions:

    <NavigateSelectionAction Type="Secondary" />

    <ToggleLayerAction Type="Secondary" />

    <CaptureDistanceAction Type="Secondary" />

    <CurrentLocationAction Type="Secondary" />

    <AutoCenterMapAction Type="Secondary" />

a.      Add to MarkerVectorLayer:

         <FeatureInfo Title="Name: @{name}" Detail="Comments: @{description}">

             <NavigateShellAction Icon="Edit" Target="LocationForm">

                 <Parameter Name="Id" Value="@{id}" />

             </NavigateShellAction>

             <NavigateSelectionAction />

         </FeatureInfo>

2.      Test App

 

Lab 3: Adding a 1:N relationship to store pictures

 

The goal of this lab is to learn how to create a one to many relationship to store, in this particular case, several pictures related to the currently selected location. 

The idea to implement such a relationship is to create an additional table (entity in our Shell) and to store for each new row the primary key of the current Location. To implement this behavior we will have the following configuration:

  1. in our LocationForm.xaml
    1. a table widget  to show the pictures already captured for the current Location
    2. a NavigateFieldAction to get the user redirected to a new form called LocationImageForm and passing the id of the Location as parameter to be stored in the entity_id of the Image
  2. a new LocationImageForm.xaml with
    1. a table widget like in the LocationForm
    2. other widgets to capture additional details about the new picture

 

1.      PostgreSql3.sql -> add image table

2.      Shell.xaml ->

a.      add to Entities:

<Entity Id="Image" Table="images" Key="id" SyncType="Automatic" RevisionField="lastupdatetime">

<Field Name="id" Type="Guid" IsRequired="True"/>

<Field Name="imagetype" Type="String"/>

<Field Name="entity_id" Type="Guid" ForeignEntity="Locations"/>

<Field Name="description" Type="String"/>               

<Field Name="image" Type="Binary" LazyLoading="True"/>

<Field Name="image_thumb" Type="Binary" LazyLoading="False"/>       

<Field Name="image_size" Type="Number"/>

<Field Name="image_mimetype" Type="String"/>                

<Field Name="lastupdatetime" Type="Timestamp"/>

</Entity>

b.      Add to MasterDetail.Views:

<Navigation Id="LocationImageNavigation">

<Form Id="LocationImageForm" Title="Images" View="LocationImageForm" Entity="{x:Reference Image}"/>

</Navigation>

3.      LocationForm.xaml -> add to Form:

<Table Name="Images" Title="Images" Entity="Image" Target="LocationImageForm" RowCount="5" LazyLoading="False">

     <Table.RowActions>

            <DownloadImageRowAction Field="image"/>

</Table.RowActions>

     <Table.Actions>

            <NavigateFieldAction Icon="Camera" Target="LocationImageForm">

                <Parameter Name="Field.Value.entity_id" Value="@{id}" />

            </NavigateFieldAction>

     </Table.Actions>

     <TableCell Name="imagetype" Title="Type"/>

     <TableCell Name="description" Title="Comment"/>

     <TableCell Name="lastupdatetime" Title="Created"/>              

</Table>

4.      Copy LocationImageForm.xaml from templates folder

5.      Test App

 

Lab 4: Adding values based on a picklist table

 

Goal of this lab is to add a new entity and use the whole table in a picker of the LocationForm using the key/value pairs (id/type fields in the newly created table loc_type).

 

1.      PostgreSql4.sql -> add table loc_type (picklist) and field type to locations

2.      Shell.xaml ->

a.      add Entity Id="LocationType":

<Entity Id="LocationType" Key="id" SyncType="Automatic" Table="loc_type">

<Field IsRequired="True" Name="id" Type="Guid" />

<Field Name="type" Type="String"/>

</Entity>

b.      Add to Entity Id="Locations":

<Field Name="type" Type="String" />

3.      LocationForm.xaml -> add to Form:

<Picker Name="type" Title="Location Type" KeyMember="id" DisplayMember="type" Items="{Entity LocationType}"/>

4.      Test App (you must wipe local data while connecting because data model has changed)

 

Lab 5a: Adding scripts to the form

 

In this lab we start adding custom actions in our form using scripts.  JavaScript functions can be executed based on several events in App lifecycle:

  • Form
    StartupScript
  • Field
    ChangeScript
  • Action
    BeforeScript
    AfterScript
  • List
    SelectionScript

The Javascript API is documented here.

 

We are going to add a function OnFormStartup to check the current status in the form and eventually set it to a new value (Open) and a custom action placed by the status entry to manually set it (for asking for approval).

 

1.      PostgreSql5.sql -> add field status to locations

2.      Shell.xaml -> add to Entity Id="Locations":

<Field Name="status" Type="String" />

3.      LocationForm.xaml ->

a.      Add to Form:

<Entry Name="status" Title="Status" IsEnabled="false"/>

b.      Add to Form:

    <Form.Scripts>

        <StartupScript Name="OnFormStartup">

            if (!Context.getValue('status')) {

                Context.setValue('status','Open');

            }

        </StartupScript>        

    </Form.Scripts>

c.      Update Entry Name="status" to (change status for requesting approval):

    <Entry Name="status" Title="Status" IsEnabled="false">

        <ScriptFieldAction Icon="Click">

            Context.setValue('status','Awaiting Approval');

        </ScriptFieldAction >           

    </Entry>

 

Lab 5b: Displaying locations in different lists based on the status

 

In this lab we are going to add a new Navigation to display the list of Locations based on the specific status (Open/Awaiting Approval). This will be handled by a Filter set in the Entity and then referenced in the two LocationNavigation and LocationToApproveNavigation.

 

1.      Shell.xaml ->

a.      add Entity.Filters to  Entity Id="Locations" to handle sql query:

<Entity.Filters>

<Filter Id="LocationsOpen" Sql="status = 'Open'" IsDefault="False" />

<Filter Id="LocationsToApprove" Sql="status = 'Awaiting Approval'" IsDefault="False" />

</Entity.Filters>   

b.      Add Navigation to handle a different list:

<Navigation Id="LocationToApproveNavigation">

<List Id="LocationToApproveList" Title="Locations To Approve" View="LocationList" Entity="{x:Reference Locations}">

</List>

</Navigation>

c.      Add List.Filters to both Navigation elements:

                                i.     Navigation id="LocationNavigation":

<List.Filters>

<FilterRef Filter="{x:Reference LocationsOpen}" Title="Locations" IsDefault="True"/>

</List.Filters>

                               ii.          Navigation id="LocationToApproveNavigation":

<List.Filters>

<FilterRef Filter="{x:Reference LocationsToApprove}" Title="Locations To Approve" IsDefault="True"/>

</List.Filters> 

 

  1. Menu.xaml ->

a.      Add Menuitem to show the new Navigation:

<MenuItem Target="LocationToApproveNavigation" Title="Locations To Approve" Icon="Work" />

 

Lab 6: Customizing via Javascript

 

In this lab we are adding 2 more custom actions.

The first one is used to fix an improper behavior while we capture pictures: if the Location has NOT been saved already and we try to capture a new Image, the newly created image will be saved without any id set in entity_id. With this custom script we are checking if the the Location has been saved (there is an id set in the form) and in case it is not we cancel the action itself.

The second action is used to customize the default behavior of the DeleteShellAction: we prompt the user if he really wants to delete the current Location, in this case we delete it, otherwise we cancel the action.

 

1.      LocationForm.xaml ->

a.      Disable camera action if location has not been saved yet

Add to <NavigateFieldAction Icon="Camera" Target="LocationImageForm">:

<NavigateFieldAction.BeforeScript>

var id = Context.getValue('id');

if (!id) {

Context.message('Location must be saved before start capturing pictures');

Context.cancel();

}

</NavigateFieldAction.BeforeScript>

b.      Ask the user for confirmation before deleting a Location

Change DeleteShellAction this way:

<DeleteShellAction.BeforeScript>

Context.alert('Would you really like to delete?', 'Yes', 'No', function (result) {

if (!result)

Context.cancel();

else

Context.done();

});

</DeleteShellAction.BeforeScript>

Comments
by sturcato
‎11-23-2018 01:14 AM - edited ‎11-23-2018 01:35 AM

Hi Wim,

 

the only difference is that the GeometryFieldAction overwrites the menu control on the top right corner to put the "Ok" and "Cancel" buttons to save the geometry. What you can do is to add an addiional script action like this:

 

<ScriptFieldAction  Icon="Gps">
	Context.setGpsPosition('geometry','accuracy');
</ScriptFieldAction >	

to set the current postiion on the map programmatically. You may also set this action in the startup script of your form, maybe checking if there is already a geometry in the current form or not.

 

UPDATE: In this case I've added an integer field to the table called "accuracy" in which I set a default value to for instance 20, since this is needed by the script action.

 

HTH,

Stefano

by ckirk
‎02-07-2019 05:21 AM - edited ‎02-07-2019 05:25 AM

Hi Stefano,

 

 

Thankyou for the Demo, i was trying different features in windows app.When i was using the 'Navaigate selection' feature in the map i get the below error.

  Error.PNG

by jovlinda
‎03-12-2019 06:14 PM - edited ‎03-12-2019 08:29 PM

Hi there,

 

I'm having a problem when uploading the zip file. The error shows internal server error when I tried to save it. I don't know what this error means.

 

If you have any idea or why does the error show that, it would be a great help.

 

Thank you,

Jovlinda

 

Edit: Nevermind, already found the error. Basically, inside the zip file another file was created.

by Bergie
on ‎04-09-2019 10:05 AM

Good Afternoon,

 

First off thank you for this very helpful tutorial!  Unfortunately though I'm having some trouble with Lab 3, I can't get the app to sync the image.  There are no errors when I save the new point in the app or when I go back and attach an image but the image never gets pushed back to the database.  When I log out and then back in it does say: "Could not sync change. Retried 5 times. (Internal Server Error)".

 

I have tried Android and iOS but both are having the issue, I do get an entry in the Device Logs but I can't deciper it.  Let me know if it would be helpful and I can upload/attach.

 

Thanks,

-Chad

Overview
Contributors