Tutorial 13

Smart Phone Applications

Prerequisites for Completing this Tutorial

 

To follow this tutorial you must have:

 

1.       Completed aXes tutorials 1 through 4.

 

2.       The ability to use the IBM i operating system, 5250 DDS and perform RPG programming. 

 

 

Overview and Objectives  

The following material provides the foundations for developing a simple generic framework for building Smart Phone applications.

 

To do this it uses a generic approach and generic implementation techniques.

 

The objective of this tutorial is to help you understand the basics of a simple generic framework for Smart Phone applications so that you can replace, evolve, extend or customize it to create your own specific framework.  

Getting Started - Check List of Objects You Need   

You need to have the AXESDEMO library installed on your system.

 

Library AXESDEMO must contain these objects:

 

Name

Type / Attribute

Description

Check

QTUTORIAL

*FILE / PF 

RPG, DDS and CL source code for examples

 

TU4DISPLAY

*FILE / DSPF

Main Display File

 

TU4DRIVER

*PGM / RPGLE

Main Driver Program

 

TU4LOGON

*PGM / CLP

Direct logon program – calls TU4DRIVER

 

TU4CUSTM2P

*PGM / RPGLE

Customer Inquiry – Method 2 example program

 

TU4CUSTM3D

*FILE / DSPF

Customer Inquiry – Method 3 example display file

 

TU4CUSTM3P

*PGM / RPGLE

Customer Inquiry – Method 3 example program

 

AXMBCUST

*FILE / PF

Customer File - DDS is in QDDSSRC

 

AXMBPART

*FILE / PF

Spare Parts File – DDS is in QDDSSRC   

 

 

Also complete this checklist:

 

Check to be performed

Check Passed

aXes development environment is installed and operational on development PC

 

aXes tutorials 1 through 4 completed

 

aXes version shows as 1.35.005 (or later). Check the bottom right of aXes-TS or aXes-TS2 login screen shows this (or a higher version number): 

 

 

Safari or Google Chrome browser installed on development PC

Safari – http://www.apple.com/safari/download/

Google - http://www.google.com/chrome

 

 

Implementing a Smart Phone Application

About This Tutorial

The following tutorial steps are designed to help you understand a variety of techniques that may be useful when implementing a smart phone application.

 

These tutorial steps do not produce a holistic result – a real smart phone application that you could use in a production environment – instead they produce a set of results that show you how to do various things that you would want to do in a real application. They should provide you with raw material that you can consolidate and extrapolate into a real application of your own design.

Create a new aXes project

To get started on this tutorial, log on to aXes as a developer and create a new project.

All the following tutorial steps should be performed within that project.  

Setting up shared code in the USERENV.JS file (USERENV object)

The USERENV.JS file and the USERENV JavaScript object are important concepts in reusing logic and in creating single maintenance points for design and layout changes.

 

In this tutorial create a sub-object of USERENV called USERENV.MOBILE by copying and pasting this starter code inside your project's USERENV object:

 

   /* ===================================================================== */

   /* Smart Phone Manager Object - all references are USERENV.MOBILE.xxxxxx */

   /* ===================================================================== */

 

   MOBILE :

   {

             /* _ prefix denote private objects that should not be referenced by eXtension scripts */ 

 

             _isiPhone         : false,

             _screenSendEnabled : false,

             _ScreenFields : {NEXTACTION:"ifld10d",INFO_1:"ifld202",INFO_2:"ifld302",INFO_3:"ifld402",INFO_4:"ifld502",INFO_5:"ifld602",

                              INFO_6:"ifld702",INFO_7:"ifld802",INFO_8:"ifld902",INFO_9:"iflda02",INFO_10:"ifldb02"},

 

             /* Exposed properties and methods that may be referenced by eXtension scripts */            

 

             currentCUSTOMER   : null,

 

             deviceWidth       : function(env) { env.returnValue = 320; },   

             deviceHeight      : function(env) { env.returnValue = 430;  },  

             deviceZoom        : function(env) { if (USERENV.MOBILE._isiPhone) env.returnValue = -1; else env.returnValue = 100; },

             lockZoom          : function(env) { env.returnValue = true; },   

 

             signOn : function(env)

             {

                USERENV.MOBILE._isiPhone = (navigator.userAgent.match(/iPhone|iPod/) != null);

                env.SHOWAXESMENUBAR(false);

                env.SHOWAXESSTATUSBAR(false);

             },

 

             signOff : function(env)

             {

                env.SHOWAXESMENUBAR(true);

                env.SHOWAXESSTATUSBAR(true);

                USERENV.MOBILE._screenSendEnabled = false

             },

 

             onArrive : function(env)

             {

                USERENV.MOBILE.screenSendEnabled = false;

             },

 

             onLeave : function(env)

             {

                env.returnValue = USERENV.MOBILE._screenSendEnabled;

             },

 

             setINFO : function(env,index,value)

             {

                var id = USERENV.MOBILE._ScreenFields["INFO_" + index.toString()]; 

                if (id == null) { alert("USERENV.MOBILE.setINFO encountered an invalid index value."); return; };

                var element = AXES.currentForm.getElementById(id);

                if (element == null) {alert("USERENV.MOBILE.setINFO cannot find specified INFO_n field element on screen."); return; };

                element.setValue(value.toString());

             },

 

             getINFO : function(env,index,value)

             {

                var id = USERENV.MOBILE._ScreenFields["INFO_" + index.toString()]; 

                if (id == null) {alert("USERENV.MOBILE.getINFO encountered an invalid index value."); return(""); };

                var element = AXES.currentForm.getElementById(id);

                if (element == null) {alert("USERENV.MOBILE.getINFO cannot find specified INFO_n field element on screen."); return(""); };

                return(element.getValue());

             },

 

             gotoScreen : function(env,nextscreen)

             {

                if (nextscreen == null) nextscreen = "HOME";

                var nextaction = AXES.currentForm.getElementById(USERENV.MOBILE._ScreenFields.NEXTACTION);

                if (nextaction == null) {alert("USERENV.MOBILE.gotoScreen cannot find NEXTACTION field."); return };

                nextaction.setValue(nextscreen);

              for (var i = 2; i < arguments.length; i++) { USERENV.MOBILE.setINFO(env,(i-1),arguments[i]); }

                USERENV.MOBILE._screenSendEnabled = true;

                env.SENDKEY("Enter");

             }  

 

   }, /* <--- Note the comma */

 

   /* ================================= */

   /* End of Smart Phone Manager Object */

   /* ================================= */

Using centralized signOn() and signOff()  logic    

Your USERENV.MOBILE object contains functions signOn() and signOff().

 

Plug them into your project by editing your application properties so that they are called at the appropriate times - like this:

 

 

The calls are

 

   USERENV.MOBILE.signOn(ENV);

 

and

 

   USERENV.MOBILE.signOff(ENV);

 

Save your project changes.

Set up Some Styles    

Next you need to set up some base styles as part of your application.

Set them into your project by editing your application properties.

In this tutorial we are going to use these styles:

 

Which have these style property values:

 

Style Item Name

Property

Value to use (double check your values)

 

background

 

 

Background

 

#27282d

 

smallText

 

Font-Family

Font-Size

Color

 

 

Verdana

10pt

White

 

mediumText

 

Font-Family

Font-Size

Color

 

 

Verdana

10pt

White

 

largeText

 

Font-Family

Font-Size

Color

 

 

Verdana

10pt

White

 

xlargeText

 

Font-Family

Font-Size

Color

 

 

Verdana

10pt

White

 

errorMessage

 

Font-Family

Font-Size

Color

 

 

Verdana

10pt

Red

 

Define these base styles into your project and save your changes.

Setting up a HOME Screen    

 

Log on as an aXes developer.

 

Add library AXESDEMO to your library list.

 

Call program TU4DRIVER – the tutorial 4 driver program written in free format ILE RPG. The source code for this program is in source file QTUTORIAL in library AXESDEMO. It has no parameters. 

 

The resulting 5250 display will look like this - which may seem a bit strange at first.

 

 

 

---------------------------------------------------------------------------------------------------------

 

Identify this screen with the name HOME - the Suggest button will do this automatically or you can type the name in:

 

 

Now click on the first field on the screen (an output field at line 1 position 2 containing the word "HOME") to select it – name the screen field THISSCREEN.

 

 

Make sure to check the identification box for this field so that it is used as part of the screen signature to uniquely identify it. 

 

Save your screen identification changes.

 

---------------------------------------------------------------------------------------------------------

 

Now start customizing this screen.

 

Hook up the USERENV.MOBILE.onArrive() and USERENV.MOBILE.onLeave() functions like this:

 

 

Then add an Auto Zoom Screen Size extension to the screen and hook up all the USERENV.MOBILE sizing functions - like this:

 

 

Now apply the background style created earlier to the whole screen:

 

 

Save your changes.

 

---------------------------------------------------------------------------------------------------------

 

Next you need to hide every 5250 field on the screen.

 

You do this by selecting each field and un-checking its default visualization extension - like this:

 

  è

 

When you save your changes you should see a completely blank screen.

 

This is a blank "virtual screen" canvas for you to start painting on:

 

 

 

Make sure that your screen is this dark colour.

 

In the following steps we are going to insert white text onto it.

 

If you start inserting white text onto a white background things can become very confusing!   

 

 

---------------------------------------------------------------------------------------------------------

 

Now add a label eXtension to your screen captioned Home Screen.

 

Use the xlargeText base style for the label to make it use the large white font. 

 

Then add a push button eXtension captioned Log Off to your screen.

 

The screen should now look something like this:

 

 

 

Change the onClick property of the push button to execute this script:

 

USERENV.MOBILE.gotoScreen(ENV,"EXIT");

 

The gotoScreen() function puts the string "EXIT" into the 5250 screen and sends the enter key. This tells the driver program TU4DRIVER to end.

 

Save your changes and then click the Log Off button – you should be returned to where you called the program TU4DRIVER from.

 

Note: In a real application a program like TU4DRIVER would be called automatically when the user signs on - so when TU4DRIVER ends the user would be logged off from the system.  More on this later. 

 

You should now be able to call up the TU4DRIVER program, which will display your HOME page, and then end it again by clicking the Log Off button. Please ensure you can do this easily by repeating the process several times before proceeding with this tutorial. 

 

You have now created a Home Page for your application.

 

It is pretty sparse at the moment – however the following tutorial steps will show you how to add functionality to it.   

 

New Screen Checklist     

For every new screen you define in this tutorial you should complete this check list:

 

Step

Action

Checked

1

The screen is named HOME, MESSAGE or VS_xxxxxxxx according to the name displayed in output field at line 1 position 2 on screen.

 

2

Output field at line 1 position 2 named THISSCREEN has been checked as an identification field

 

 

3

The THISSCREEN field at line 1 position 2 displays the same screen name as you input in step 1 (i.e.: you have given the screen the correct name). 

 

4

Screen identification details have been saved

 

5

Screen customization started

 

6

Screen onArrive and onLeave events execute correct USERENV.MOBILE functions:

 

onArrive

USERENV.MOBILE.onArrive(ENV);

onLeave

USERENV.MOBILE.onLeave(ENV);

 

 

 

7

Auto Zoom Screen Size has been set up like this:

(the properties need to be set to evaluate script mode)

 

width

USERENV.MOBILE.deviceWidth(ENV);

height

USERENV.MOBILE.deviceHeight(ENV);

zoom

USERENV.MOBILE.deviceZoom(ENV);

lockZoom

USERENV.MOBILE.lockZoom(ENV);

 

 

 

8

The base style backGround has been applied to whole screen:

 

9

All unwanted 5250 fields on the screen have been hidden from view by un-checking their default visualization property:

 

10

Screen customization changes saved

 

 

Setting Up a Messages Screen    

It's useful to have a generic messages screen in smart phone applications.

 

---------------------------------------------------------------------------------------------------------

 

To set up a messages screen do the following:

 

Call program TU4DRIVER to display your Home Page.

 

Add a new push button to your Home Page captioned Messages that calls a Message screen when clicked.

 

USERENV.MOBILE.gotoScreen(ENV,"MESSAGE");

 

Save your changes. Your home screen should now look something like this:

 

 

 

---------------------------------------------------------------------------------------------------------

 

Click the Message button. The result should look like this:

 

This is a brand new blank canvas virtual screen (more about them later).

 

This screen should be named MESSAGE.

 

---------------------------------------------------------------------------------------------------------

 

Complete the preceding New Screen Checklist to set this screen up for proper smart phone operations – you should end up with a completely blank screen.

 

---------------------------------------------------------------------------------------------------------

 

Now add a new label eXtension ("Messages") and two new push button eXtensions ("Home" and "Log Off") to your messages screen.

 

The Home button should do this when clicked or touched:

 

      USERENV.MOBILE.gotoScreen(ENV,"HOME");

 

The Log Off button should do this when clicked or touched:

     

     USERENV.MOBILE.gotoScreen(ENV,"EXIT");

 

Your MESSAGE screen should now look like this:

 

 

Save your changes.

 

---------------------------------------------------------------------------------------------------------

 

Now add a new label eXtension to the middle of your MESSAGE screen - something like this:

 

 

 

Use base style mediumText so that text is largish and easy to read.

 

Now change the text property of the label so that the content it is dynamically created.

 

The script you need to use is something like this:

 

var text = "";

for (var i = 1; i <= 10; i++) { text += USERENV.MOBILE.getINFO(ENV,i); }

if (text == "") text = "No messages are available at this time.";

ENV.returnValue = text;

 

What this script does is retrieve the contents of the hidden 5250 fields and assemble them into one long text string. The resulting string is displayed in the label eXtension.

 

Save your changes.

 

---------------------------------------------------------------------------------------------------------

 

Your MESSAGE screen should now look like this:

 

 

You should now be able to start up the smart phone application by calling TU4DRIVER to display your HOME screen.

From the HOME screen you can display the MESSAGE screen, and from there you can go back to the HOME screen or EXIT (log off).

 

Please check you can do all these things before proceeding. 

Presenting Information on a Smart Phone

The following tutorial steps are going to implement a Customer Details Inquiry using three different methods.

 

·         Method 1: The inquiry is controlled by the client side scripting - using SQL to extract the customer details.

 

·         Method 2: The inquiry is controlled by the client side scripting – but uses a service or subroutine style RPG program to extract the required customer details.

 

·         Method 3: The inquiry is initiated by client side scripting – but the presentation is performed and ultimately managed and validated by a classic 5250 RPG program.

 

Obviously doing the same thing three different ways is not the objective of this tutorial.

 

The objective is to help you to understand the three main choices you have for common forms of information presentation from a smart phone.

 

By completing these tutorial steps you should be able to compare and contrast the advantages and disadvantages of each method – allowing you to make the best choice for real scenarios that you encounter.

 

Customer Inquiry

 

Start aXes as a developer and call program TU4DRIVER to display your HOME screen.

 

Add to your HOME screen:

  • A group box eXtension,
  • An input field eXtension (= default visualization)
  • Three push buttons eXtensions

 

Position, style and label them like this:

 

 

You need to set the style of the group box to use a white font.

 

Make sure that the input eXtension is:

 

·         named CUSTOMERNUMBER

·         has its maximumInputLength property set to 7

 

Like this:

 

 

Save your customization changes.

 

---------------------------------------------------------------------------------------------------------

 

Optional Technical Notes:

Try clicking your three new Details push buttons - notice how nothing happens?

This is because your home screen has on onLeave function like this:

 

 

If you look at the onArrive and onLeave functions in USERENV.MOBILE they do this:

 

             onArrive : function(env)

             {

                USERENV.MOBILE.screenSendEnabled = false;

             },

 

             onLeave : function(env)

             {

                env.returnValue = USERENV.MOBILE._screenSendEnabled;

             },

 

Every time a screen arrives the property USERENV.MOBILE.screenSendEnabled is set to false.

 

Every time the screen tries to leave (e.g.: when you click one of the new Details buttons) the current value of USERENV.MOBILE._screenSendEnabled is returned back to the aXes driver to indicate whether to proceed or not.

 

So when you click one of the new Details buttons the value being returned is false – so the request to send details to the server (i.e.: leave this screen) is ignored.     

 

The important matching code is in:

 

            gotoScreen : function(env,nextscreen)

            {

                <unrelated logic has been omitted>

                USERENV.MOBILE._screenSendEnabled = true;

                env.SENDKEY("Enter");

             }  

 

When you invoke USERENV.MOBILE.gotoScreen() it sets the blocking property screenSendEnabled to true – which means that the subsequent SENDKEY("Enter") will be sent back to the server.

 

In other words - the only way to submit a request to the server is by using USERENV.MOBILE.gotoScreen() – any other scripted or user imitated use of the Enter key, function keys (which don’t exist on smart phones anyway) are all ignored.    

Method 1 - Using Client Logic Only 

One of the ways you can define screens for presenting information is to use a virtual screen.

 

A virtual screen is one that does not need a specialized 5250 program on the server to create its visual content or behaviour. The visual content typically comes from execution of scripts and server side SQL requests.

 

The screen content is assembled and controlled entirely by the client logic.

 

---------------------------------------------------------------------------------------------------------

 

First, define a dynamic SQL request in your project's Dynamic Tables file. This defines an SQL command to find a specified customer and creates an aXes table named AXMBCUST-INQUIRE: 

 

    DefineObjectInstance {

      className          = "DynamicTable",

      name               = "AXMBCUST-INQUIRE",  

      source             = "sql",

      selectSQLcommand   = "CUSTNUMBR,CUSTNAME,CUSTADDR,CUSTCITY,CUSTZIP,CUSTPHONE,CUSTEMAIL from AXESDEMO.AXMBCUST where CUSTNUMBR = :SQLVariable_CUSTOMERNUMBER",

      resultColumnNames  = { "CUSTNUMBR","CUSTNAME","CUSTADDR","CUSTCITY","CUSTZIP","CUSTPHONE","CUSTEMAIL" },

    };  

 

Save your changes and follow any restart instructions.

 

---------------------------------------------------------------------------------------------------------

 

Now add this code to your Details – Meth 1 button's click handling:

 

/* Default the things to do next */

var NEXTACTION = "MESSAGE";

var INFO_1 = "";

 

/* Get the customer number from the current screen as number */

 

var iCustNo = parseInt(FIELDS("CUSTOMERNUMBER").getValue(),10);

 

/* If the customer number is not valid goto message screen */

 

if ((isNaN(iCustNo))||(iCustNo < 1)||(iCustNo > 9999999))

{

   INFO_1 = "Customer number " + iCustNo.toString() + " is not a valid customer number.";

}

else

{

 

   /* Ask the manager to load the dynamic table, passing the customer number as an SQL variable */

   TABLEMANAGER.loadDynamicTable("AXMBCUST-INQUIRE",USERENV.dynamicTablesFile,{SQLVariable_CUSTOMERNUMBER:iCustNo.toString()});

 

   /* Get the first row from the aXes table produced by executing the SQL command */

   USERENV.MOBILE.currentCUSTOMER = TABLEMANAGER.getTable("AXMBCUST-INQUIRE").child(0); 

 

   /* If not found then no customer with the number exists so go to message screen */

   if (USERENV.MOBILE.currentCUSTOMER == null)

     INFO_1 = "No customer with customer number " + iCustNo.toString() + " can be found on the server.";

 

   else

      NEXTACTION = "VS_CUSTM1"; 

}

 

/* Proceed on to the next action/screen */

 

USERENV.MOBILE.gotoScreen(ENV,NEXTACTION,INFO_1);

 

 

This script:

  • Retrieves and validates the CUSTOMERNUMBER entered by the user.

·         Executes the SQL command defined in the dynamic SQL table (AXMBCUST-INQUIRE).

·         If a row (record) is found it goes to the screen named VS_CUSTM1.

·         If a row (record) cannot be found it goes to the screen named MESSAGE.

 

 

Try out your Details – Meth 1 by entering numbers 1111111 and 999999. They should cause your MESSAGE screen to be displayed.

 

---------------------------------------------------------------------------------------------------------

 

Now try out a valid number like 1 or 6.

 

The will cause a brand new screen named VS_CUSTM1 to be displayed, something like this:

 

 

You should recognize this type of screen now – it is a "blank" virtual screen that you have decided to name VS_CUSTM1.

 

---------------------------------------------------------------------------------------------------------

 

Set VS_CUSTM1 up in the normal manner by completing all the steps in the preceding New Screen Checklist table.

 

---------------------------------------------------------------------------------------------------------

 

Then add a title Customer Details and also Home and Log Off buttons to your new VS_CUSTM1 screen so that you have a blank canvas starting point like this:

 

 

The Log Off button's script should do this: USERENV.MOBILE.gotoScreen(ENV,"EXIT");

The Home button's script should do this: USERENV.MOBILE.gotoScreen(ENV,"HOME");    

      

Check that your buttons work as expected.

 

Now add and style a label eXtension on the screen that has text property "Name:".

 

Then add and style another label eXtension beside it.

 

Set its text property by evaluating this script:

 

        ENV.returnValue = USERENV.MOBILE.currentCUSTOMER.CUSTNAME;   

 

Save your changes.

 

---------------------------------------------------------------------------------------------------------

 

You should see a customer name appear on the screen like this:

 

 

---------------------------------------------------------------------------------------------------------

 

To recap – back on your home screen an SQL command was executed when a customer number was entered and the Details – Meth 1 button was clicked.

 

 

 

The SQL command produced an aXes table that had row elements named:

 

  "CUSTNUMBR","CUSTNAME","CUSTADDR","CUSTCITY","CUSTZIP","CUSTPHONE","CUSTEMAIL"

 

It also set a reference to the first aXes table row into the USERENV.MOBILE object like this:

 

   USERENV.MOBILE.currentCUSTOMER = TABLEMANAGER.getTable("AXMBCUST-INQUIRE").child(0); 

 

So ….

 

   USERENV.MOBILE.currentCUSTOMER.CUSTNAME;   

 

contains the name of the selected customer.

 

And equally ….

 

     USERENV.MOBILE.currentCUSTOMER.CUSTPHONE;

 

contains the customer's phone number.    

 

So by using the information in USERENV.MOBILE.currentCUSTOMER you should be able to produce a screen that looks something like this:

 

       

Save all your changes and test your inquiry with a number of different customer numbers. 

 

---------------------------------------------------------------------------------------------------------

 

You have now built a basic customer inquiry.

 

The key thing to understand is that you did this by using a virtual screen and by client side scripting alone.

 

You did not need to build any special-purpose server-side RPG programs to do this.  

 

Time to try out the Real Thing via Desktop, Phone or Emulator 

 

Before looking at the other two ways you can do a customer inquiry, it is probably worth going through how you can test your application as the "real thing".

 

Up until now you have been running driver program TU4DRIVER by calling it from command entry. For application development that is fine – but in a real application you would want to run it as soon as the user logged on.

 

In the AXESDEMO library there is a CL program called TU4LOGON that does this:

 

 PGM                                           

                                              

 DCL        VAR(&USER) TYPE(*CHAR) LEN(10)    

                                              

 CHGJOB     BRKMSG(*HOLD) STSMSG(*NONE)       

 MONMSG     MSGID(CPF0000 MCH0000)            

                                               

 RTVJOBA    USER(&USER)                       

 MONMSG     MSGID(CPF0000 MCH0000)            

                                              

 CLRMSGQ    MSGQ(*WRKSTN)                     

 MONMSG     MSGID(CPF0000 MCH0000)            

                                              

 CLRMSGQ    MSGQ(&USER)                       

 MONMSG     MSGID(CPF0000 MCH0000)            

                                              

 ADDLIBLE   LIB(AXESDEMO)              

 MONMSG     MSGID(CPF0000 MCH0000)     

                                       

 CALL       PGM(TU4DRIVER)             

 MONMSG     MSGID(CPF0000 MCH0000)     

                                       

 SIGNOFF                               

                                        

 ENDPGM                                

 

 

TU4LOGON can act as a simple user logon program for purposes of this tutorial.

 

You will probably need to duplicate program Tu4LOGON from library AXESDEMO into a library that it is in your user profile's library list (e.g.: QGPL).

 

Next - typing in long URLs on a smart phone is error prone. You can improve this situation by making a simple HTML document in the root of your aXes system.

 

For example, if you create a file named TUT4.HTML in the root of your aXes system containing this HTML ….  

 

<html>

<head>

</head>

<body>

<script type="text/javascript">

window.location.replace("http://<aXesHost>/ts/ts2/mobile.html?definitionSet=<ppppp>&user=<uuuuu>&program=TU4LOGON");

</script>

</body>

</html>

   

Where:

  • <aXesHost> is your aXes Host
  • <pppppp> is your project folder's name
  • <uuuuuu> is your user profile name.

 

Note: After creating file TU4.HTML make sure that user *PUBLIC has *R (and only *R) access rights to the file. Use the IBM i WRKLNK command to check and change this.  

 

Now on your phone you can enter the simplified URL instead:

 

http://<axes Host>/tut4.html

 

One other thing worth noting is that ultimately it is mobile.html that is opened to access aXes – not the default index.html. This causes an aXes mobile session to be started instead of a normal aXes-TS type 5250 session.

 

This example causes program TU4LOGON to be started by specifying it on the 5250 logon screen. Your IBM i system configuration might not allow this. If so, you should set up a testing user profile that has TU4LOGON specified as its initial program.       

 

Having set up a simple entry point like http://<axes Host>/tut4.html you can now try out your application for real in a number of ways:

 

·         From a smart phone such an iPhone or an Android 2.1 (or later) phone.

 

·         From a desktop browser – but you must use Safari or Chrome - you cannot use IE. 

 

·         In a phone emulator or simulator. These are available for Windows and Mac systems. The complexity of their set up varies and is beyond the scope this tutorial. 

 

For example, you can test your application:

 

In the Safari browser on Windows desktop:

 

 

In an iPhone emulator on a Mac system:

 

 

In an Android emulator:

 

 

 

You should try your application out on one of these test platforms.

 

Remember that ultimately you must try out your application on a real Smart Phone.

 

Method 2 - Using a Service or Subroutine Program Approach 

 

In the customer inquiry method 1 tutorial you built a virtual screen to display customer details. This was done entirely by the client and no specialized server RPG side RPG program was required.

                                                                               

The second example involves creating an RPG service or subroutine style program (it is called a service or subroutine style program because it provides a service to the smart phone application without having a user interface of its own).

 

First you need to write and compile your RPG "service" or "subroutine" program.

 

The shipped example is TU4CUSTM2P with the source code in the QTUTORIAL file.

 

-------------------------------------------------------------------------------------------------------

 

The RPG code looks like this:

 

FAXMBCUST  IF   E           K DISK                              

 D/copy QTUTORIAL,TU4INCLUDA                                     

 C     *ENTRY        PLIST                                       

 C                   PARM                    StateBlock           

 C/free                                                          

      CustNumbr = %dec(Info_1:7:0);                              

      StateBlock = ' ';                                          

      Chain CustNumbr AXMBCUSTR;                                  

      If NOT %Found(AXMBCUST);                                   

         Info_1 = 'No customer with number ' + %char(CustNumbr)  

                + ' could be found.';                            

          NextAction = 'MESSAGE';                                

      else;                                                      

          info_1 = %char(CustNumbr);                             

          info_2 = CustName;                                     

          info_3 = CustAddr;

          info_4 = CustCity;                          

          info_5 = CustZip;                           

          info_6 = CustPhone;                         

          info_7 = CustEmail;                         

          NextAction = 'VS_CUSTM2';                   

     endif;                                          

     *inlr = *on;                                    

     return;                                         

 /end-free

 

-------------------------------------------------------------------------------------------------------

 

This program receives a data structure parameter named StateBlock (defined by the /COPY member TU4INCLUDA).

 

StateBlock contains sub-fields NEXTACTION and INFO_1 through INFO_10.   

 

Logically it does this:

 

·         Extracts a customer number from the INFO_1 field passed in.

·         Reads the associated customer record (row) from file (table) AXMBCUST.

·         If not found, it sets INFO_1 to an error message and NEXTACTION to 'MESSAGE'.

·         Otherwise it maps the customer details into fields INFO_1 through INFO_7 and NEXTACTION to 'VS_CUSTM2'.                                          

                      

If you want to make your own version of this program, copy the source code from member TU4CUSTM2P in source file and compile it with a different name.                                                                        

 

-------------------------------------------------------------------------------------------------------

                                                              
Now log on to aXes as a developer.

 

Go to your applications HOME page by calling TU2DRIVER and set up the onClick scripting for your Details – Meth 2 button.    

 

   

 

The scripting you need is something like this:

 

var sCustNo = FIELDS("CUSTOMERNUMBER").getValue();

 

var iCustNo = parseInt(sCustNo,10);

 

if ((isNaN(iCustNo))||(iCustNo < 1)||(iCustNo > 9999999))

   alert("Customer number " + sCustNo + " is not a valid customer number.");

 

else

   USERENV.MOBILE.gotoScreen(ENV,"TU4CUSTM2P",sCustNo);

 

The logic is:

  • The customer number is crudely validated.
  • If it is no good, a message box is displayed.
  • Otherwise the TU4DRIVER program is instructed to call program TU4CUSTM2P, passing the customer number value into it in field INFO_1 (if you have your own program use its name instead of TU4CUSTM2P).   

 

 

Now try out your Details – Meth 2 button with some bad customer numbers first to check the error handling.

 

-------------------------------------------------------------------------------------------------------

 

Now try a valid customer number - like 1, 2 or 5.

 

The resulting screen should look something like this:

 

 

By now you should be able to identify this as a new virtual screen named VS_CUSTM2.

 

You can also see the information returned by RPG program TU4CUSTM2P (or your version).

 

On the new virtual screen named VS_CUSTM2 you should now complete these steps:

 

·         Complete the preceding New Screen Checklist activities.

 

·         Add and style a title like "Customer Details Meth 2"

 

·         Add a Home push button that does USERENV.MOBILE.gotoScreen(ENV,"HOME");

 

·         Add a Log Off push button that does USERENV.MOBILE.gotoScreen(ENV,"EXIT");

 

·         Add and style a label with text property "Name:" 

 

·         Add and style a label beside the name that sets its text by executing the script ENV.returnValue = USERENV.MOBILE.getINFO(ENV,2);

 

·         Add and style a label with text property "Address:" 

 

·         Add and style a label beside the name that sets its text by executing the script ENV.returnValue = USERENV.MOBILE.getINFO(ENV,3);

 

The result should look something like this:

 

 

By adding more labels you can display the values of 5250 fields INFO_4 (City), INFO_5 (Zip Code), INFO_6 (Phone Number) and INFO_7 (Email address) by using the getINFO(ENV,N) function to retrieve the values. This equates directly to these lines in the RPG program TU4CUSTM2P (or your version of it):

 

          info_1 = %char(CustNumbr);                             

          info_2 = CustName;                                     

          info_3 = CustAddr;

          info_4 = CustCity;                          

          info_5 = CustZip;                            

          info_6 = CustPhone;                         

          info_7 = CustEmail;                         

   

The key point to understand in this method is that the data extraction is performed by an RPG program – but the final mapping of that information onto the screen is performed by client side scripting. Here the server side RPG program TU4CUSTM2P (or your version) is acting as a "service" or "subroutine" to the client side logic.     

 

 

Optional Technical Note:

The INFO_1 through INFO_10 fields are used to map data into and out of RPG programs.

 

There are only 10 of these fields in the tutorial – but of course you could add more.

 

Also note that they are 130 bytes long (aXes nearly always uses 132 wide screens) – so by specific positioning or by using the separator character and the JavaScript "split" function you can easily and generically compact multiple items into one 5250 screen field.   

 

There are also various other techniques for passing very large amounts of data from RPG programs out to the client application - including data queues and JSON strings. Contact your product vendor for more details and examples. 

 

Method 3 - Using a classic 5250 RPG Program 

In the customer inquiry method 1 tutorial you built a virtual screen to display customer details. This was done entirely by the client and no specialized server RPG side RPG program was required.

                                                                               

The method 2 tutorial involved creating an RPG service or subroutine program. It was called to return agreed values which the client side then arranged on the screen.

 

The final method (3) involves using an RPG program that uses a real 5250 screen. This is classical way of presenting information from an RPG program – possibly the way that you are most familiar with.

 

-------------------------------------------------------------------------------------------------------

 

The display file is named TU4CUSTM3D and its DDS looks like this:

 

A                                      DSPSIZ(27 132)            

A                                      REF(AXMBCUST)             

A          R RECORD                                              

A            THISSCREEN    10A  B  1  2DSPATR(PR)                

A            NEXTACTION    10A  B  1 13                           

A                                  3  2'Number'                  

A                                  4  2'Name'                    

A                                  5  2'Address'                 

A                                  6  2'City'                    

A                                  7  2'Zip Code'                

A                                  8  2'Phone'                   

A                                  9  2'Email'                   

A            XUSTNUMBR R        B  3 20REFFLD(CUSTNUMBR)         

A            XUSTNAME  R     O  B  4 20REFFLD(CUSTNAME) CHECK(LC)

A            XUSTADDR  R     O  B  5 20REFFLD(CUSTADDR) CHECK(LC)

A            XUSTCITY  R     O  B  6 20REFFLD(CUSTCITY) CHECK(LC)

A            XUSTZIP   R        B  7 20REFFLD(CUSTZIP)  CHECK(LC)   

A            XUSTPHONE R        B  8 20REFFLD(CUSTPHONE) CHECK(LC)  

A            XUSTEMAIL R        B  9 20REFFLD(CUSTEMAIL)  CHECK(LC) 

A            ERRORMSG     700O  O 10 20                 

 

This a really simple set of DDS. A couple of things worth noting are:

 

·         The use of fields THISSCREEN and NEXTACTION on line 1. These allow this screen to be easily hooked into the logic of driver program TU4DRIVER. They will be hidden on the resulting screen of course.

 

·         The 700 byte ERRORMSG field on line 10 position 20. This will be used to send composite error message details out to the smart phone. There is no need to worry about the length – only as much data as the field contains is actually transmitted – not all 700 bytes. 

 

·         The simplicity of the screen layout. All the labels are arranged down the screen starting at position 2 and all the data fields similarly at position 20. The reason for this simple layout is that you are going to move these fields around and even change the way they are visualized in the final result – so any consideration of 5250 screen positions is really moot. It is probably easier to create DDS like this by editing the DDS source file instead of using a 5250 screen design facility. Smart phone screens are ultimately not 5250 screens in the normal sense - so don’t waste time "designing" the 5250 screen layouts as 5250 screens.     

 

-------------------------------------------------------------------------------------------------------

 

The associated RPG program is named TU4CUSTM3P and its RPG code looks like this:

 

FTU4CUSTM3DCF   E             WORKSTN                                

FAXMBCUST  UF   E           K DISK                                   

D/copy QTUTORIAL,TU4INCLUDA                                          

D                 DS                                                  

D ThisProgram                         Like(ThisScreen)               

D Request                             Like(Info_1)                   

D ErrorCount                     7P00                                

C     *ENTRY        PLIST                                             

C                   PARM                    StateBlock               

C/free                                                               

                                                                     

     ThisProgram = ThisScreen;                                       

                                                                     

     Dou (NextAction <> ThisProgram);                                

                                                                      

        Request  = Info_1;                                           

        Monitor;                                                

           CustNumbr  = %dec(Info_2:7:0);                       

        On-Error 105;                                           

           CustNumbr  = 0;                                      

        EndMon;                                                 

                                                                  

        StateBlock = ' ';                                       

        ThisScreen = ThisProgram;                               

        NextAction = ThisProgram;                               

        Info_1     = 'UPDATE';                                   

        Info_2     = %char(CustNumbr);                          

        ErrorCount = 0;                                         

        ErrorMsg   = 'NONE';                                    

                                                                  

        if (Request = 'UPDATE');                                

           Exsr Update_Customer;                                

        else;                                                   

           Exsr Display_Customer;                               

        endif;                                                  

                                                                

        If (NextAction = ThisProgram);                          

          Exfmt Record;                                          

        Endif;                                                  

                                                                

     EndDo;                                                     

                                                                 

     *inlr = *on;                                               

     return;                                                    

     // ---------------------------------------------           

     Begsr  Display_Customer;                                   

        Chain CustNumbr AXMBCUSTR;                              

        If NOT %Found(AXMBCUST);

            StateBlock = ' ';

            Info_1 = 'No customer with number ' + %char(CustNumbr) 

                      + ' could be found (from TU4CUSTM3P)';          

            NextAction = 'MESSAGE';                                   

         else;                                                        

            Unlock AXMBCUST;                                           

            Exsr Map_Out;                                             

         Endif;                                                       

      Endsr;                                                          

      // ---------------------------------------------                

      Begsr  Update_Customer;                                         

         Exsr Validate_Customer;                                      

         If (ErrorCount = 0);      

            StateBlock = ' ';                                  

            Chain CustNumbr AXMBCUSTR;                                

           If NOT %Found(AXMBCUST);                                  

              Info_1 = 'No customer with number ' + %char(CustNumbr) 

                     + ' could be found (from TU4CUSTM3P)';

           else;                                                  

              Exsr Map_In;                                        

              Update AXMBCUSTR;                                    

              Info_1 = 'Details of customer ' + %trim(CustName)   

                     + ' have been sucessfully updated.';         

           Endif;                                                 

           NextAction = 'MESSAGE';                                

        Endif;                                                    

     Endsr;                                                       

     // ---------------------------------------------             

     Begsr  Validate_Customer;                                    

        ErrorMsg = ' ';                                           

        If (XustName = ' ');                                      

           ErrorCount += 1;                                       

           ErrorMsg = %trim(ErrorMsg)                             

                    + ' A customer name is required.';

        endif;                                                          

        If (XustAddr = ' ');                                           

           ErrorCount += 1;                                            

           ErrorMsg = %trim(ErrorMsg)                                  

                    + ' An address is required for all customers.';    

        endif;                                                         

        If (XustPhone = ' ');                                          

           ErrorCount += 1;                                             

           ErrorMsg = %trim(ErrorMsg)                                  

                    + ' A phone number is required for all customers.';

        endif;                                                         

        If (ErrorCount = 0);                                            

           ErrorMsg = 'NONE';                                          

        Endif;                                                         

     Endsr;                                                             

      // ---------------------------------------------   

     Begsr  Map_Out;                                    

        XustNumbr = CustNumbr;                          

        XustName  = CustName;                           

        XustAddr  = CustAddr;                           

        XustCity  = CustCity;                           

        XustZip   = CustZip;                            

        XustPhone = CustPhone;                          

        XustEMail = CustEMail;                          

     Endsr;                                             

     // ---------------------------------------------   

     Begsr  Map_In;                                     

        CustName  = XustName;                           

        CustAddr  = XustAddr;                           

        CustCity  = XustCity;                           

        CustZip   = XustZip;                            

        CustPhone = XustPhone;

        CustEMail = XustEMail;    

     Endsr;                       

 /end-free                                  

 

TU4CUSTM3P a fairly simple RPG program. A couple of things worth noting are:

 

·         It's designed to be called by TU4DRIVER because it has the common StateBlock parameter (a data structure defined in RPG source member TU4INCLUDA).  

 

·         It loops until the client instructs it to do something else - in which case it ends and yields control back to TU4DRIVER.

 

·         It can display customer details.

 

·         It can update customer details.

 

·         It has validation rules that can cause an update to be rejected.

 

 

-------------------------------------------------------------------------------------------------------

 

First you need to write and compile your 5250 display file and the RPG program.

 

The shipped example display file is TU4CUSTM3D (source in QTUTORIAL) and the RPG program is called TU4CUSTM3P (source in QTUTORIAL).

 

You can either use the shipped objects (which are already compiled) or copy the source code and create your own versions with different names.

 

-------------------------------------------------------------------------------------------------------

 

Next, log on to aXes as a developer, go to your application’s home page by calling TU4DRIVER and set up the onClick scripting for your Details – Meth 3 button    

 

   

 

The scripting you need is something like this:

 

/* Get the customer number from the screen */

 

var sCustNo = FIELDS("CUSTOMERNUMBER").getValue();

 

/* Invoke program TU4CUSTM3P sending request and customer number */

 

USERENV.MOBILE.gotoScreen(ENV,"TU4CUSTM3P","DISPLAY",sCustNo);

 

 

Now try out your Details – Meth 3 button.

 

This time the screen displayed is not a virtual screen – it is a real 5250 screen presented by program TU4CUSTM3P according to the DDS defined in display file TU4CUSTM3D.

 

By now you should know the drill – HOWEVER – in this case most of the fields on the screen should not be hidden.    

 

Fields THISSCREEN (line 1 pos 2), NEXTACTION (line 1 pos 13) and ERRORMSG (line 10 pos 20) should be hidden - all of the other fields should be left visible.  

 

Additionally, the long error message field name on line 10 at position 20 should be named ERRORMSG in the aXes screen definition, like this:

 

 

Save your screen definition changes after you apply a name to the ERRORMSG field.

 

-------------------------------------------------------------------------------------------------------

 

Now you should:

  • Complete the New Screen Checklist
  • Add a screen title "Customer Details – Method 3".
  • Add the standard "Log Off" and "Home" push buttons
  • Move and size the other label and input fields. Style the labels. 
  • Add a "Save Changes" push button. Execute this script when it is clicked: 

 

USERENV.MOBILE.gotoScreen(ENV,"TU4CUSTM3P"); 

 

The resulting screen looks something like this (note that it has slightly different style to the screens used in the preceding tutorial steps):

 

   

Save all your screen customization changes.

 

-------------------------------------------------------------------------------------------------------

 

Now add a label eXtension to your screen and apply base style errorMessage to it, position it in a free area on your screen – something like this:

 

 

Change it so that its text property is derived by executing this script:

 

 

 

ENV.returnValue = "";

sError = FIELDS("ERRORMSG").getValue();

if (sError != "NONE") ENV.returnValue = "Error =>" + sError; 

 

This script gets the value of the field you named ERRORMSG (which is hidden from view) and puts its value into the eXtension – providing that it does not contain the message "NONE".

 

The end result is that when you try to update a customer with a blank name, address or phone number the messages are made visible to the user …   

 

 

Save your customization changes and test your new screen. Try saving after blanking out the customer name.

 

-------------------------------------------------------------------------------------------------------

 

There are many ways to present error messages and this technique is very simple.

 

Its main benefit is that it shows all the error messages to the user without needing another screen interaction. When designing a real application you should develop a standard way to show error messages and use it consistently on all screens.

 

Notice that when you update a customer screen your MESSAGE screen is displayed to confirm the action to the user:

 

 

Doing this type of positive confirmation of user's actions is useful on smart phones where variable response times are common.  

 

The "Messages" button on your Home screen is now redundant.

 

In this application there is no reason for the user to display the messages (and in fact it may show incorrect details at times). Confirmation messages are presented automatically by the application when it is appropriate.

 

Remove the "Messages" button from your home page now and save your changes.

 

Review of the 3 Interface and Access Methods 

 

In the last 3 tutorial steps the 3 main ways of assembling and processing information on smart phone screens has been covered. These are:

 

Method

Description

Virtual Screen Used

Characteristics

1

Client Side

Yes

The client scripting dynamically creates the screen content entirely by executing script and SQL commands, etc. No special server side RPG logic is required to do this. 

2

Client and "Service" or "subroutine" program

Yes

The client scripting executes an RPG (or even CL) server side program as a service or subroutine to gather or process information required for the client side screen.

3

Server 5250 program

No

A classic RPG 5250 server program is used. It processes information through classic 5250 DDS. The client side is limited to just arranging how the information is presented. 

 

If you understand all three of these methods you should be able to decide which one to apply to which problem when designing and implementing a smart phone application.

 

The following tutorial steps are optional – they cover a broad range of topics that you may not need to know about right now.

Optional Steps

Client Side Validation

In the preceding Customer Details – Method 3 example data validation is performed by server RPG program TU4CUSTM3P. You can also easily do client side validation. Display your Customer Details – Method 3 screen and name the input fields as indicated.  

 

 

Since these are real 5250 screen fields and not newly added eXtensions you name them here:

 

 

Save your changes.

 

Now locate the screen level onLeave property and change it to execute this script:

 

var CUSTNAME = FIELDS("CUSTNAME").getValue();

var CUSTADDR = FIELDS("CUSTADDR").getValue();

var errormessage = "";

 

if (CUSTNAME == "") errormessage += " You must specify a customer name.";

if (CUSTADDR == "") errormessage += " You must specify a customer address.";

 

if (errormessage != "")

{

   alert(errormessage);

   ENV.returnValue = false; /* Stop send of data to server */

}

else

{

   USERENV.MOBILE.onLeave(ENV);

}     

 

Save your changes.

 

You should now not be able to save customer changes unless you have specified a name and address – and when the data is invalid it is stopped before it is sent to the server.

 

Validating at the client and then (re)validating at the server is a strongly recommended practice. 

Remembering Values and Initial Values 

 

In the preceding tutorial steps you may have noticed that the customer number is lost every time you (re)display the home page. This could be annoying and it is easily solved.

 

Edit the USERENV object and add a new property to your USERENV.MOBILE object definition:

 

 

             currentCUSTOMER   : null,

 

             HOME_CustomerNumber : "1", /* Remembered Customer Number */

 

             deviceWidth       : function(env) { env.returnValue = 320; },  

 

 

Save your USERENV changes and follow any restart instructions.

 

On your home page the field where they enter the customer number is named CUSTOMERNUMBER:

 

 

 

Change the field CUSTOMERNUMBER to derive its value by executing this script:

 

         ENV.returnValue = USERENV.MOBILE.HOME_CustomerNumber;

   if (USERENV.MOBILE.HOME_CustomerNumber != null)

   {

      FIELD.setValue(USERENV.MOBILE.HOME_CustomerNumber);

   }

 

 

Change the onLeave event of your home page to be like this:

 

USERENV.MOBILE.onLeave(ENV);

USERENV.MOBILE.HOME_CustomerNumber = FIELDS("CUSTOMERNUMBER").getValue();

 

 

You should now see that as you start the application the default value of "1" is displayed initially and that when you go back to the home page the last value entered is remembered.

 

On phones data entry can be difficult – so the more places you can remember last used values and set initial defaults that do not need to be changed, the better for the phone user.

 

Ease of Use – Current and Dense Information Presentation 

Smart phone applications are generally harder to work with than devices with full keyboards.

 

You can make the user's ability to select things easier by maintaining the concept of the "currently selected thing" (e.g.: the current Order, Product, Customer, Spare Part, etc).     

 

To demonstrate this approach, add this to your project's static tables file:

 

DefineObjectInstance {

      className          = "StaticTable",

      name               = "AXMBPART",  

      source             = "sql",

      selectSQLcommand   = "PARTNUMBR,PARTDESC,PARTAVAIL,PARTWHOLE,PARTRETL,PARTGIFFL from AXESDEMO.AXMBPART ORDER BY PARTDESC ",

      resultColumnNames  = { "PARTNUMBR","PARTDESC","PARTAVAIL","PARTWHOLE","PARTRETL","PARTGIFFL" }     

    };

 

This will create an aXes static table named AXMBPART from the spare parts data base table AXMBPART in the AXESDEMO library.  

 

Then add the highlighted lines to your USERENV.MOBILE object definition:

 

             lockZoom          : function(env) { env.returnValue = true; },   

 

             curAXMBPART : null,  /* Reference to current AXMBPART row */

 

             signOn : function(env)

             {

                USERENV.MOBILE._isiPhone = (navigator.userAgent.match(/iPhone|iPod/) != null);

                env.SHOWAXESMENUBAR(false);

                env.SHOWAXESSTATUSBAR(false);

 

                /* Load all static tables */               

                env.TABLEMANAGER.loadStaticTables(USERENV.staticTablesFile,null,false);

               

                /* Set a reference to the first row in the AXMBPART table */

                if (this.curAXMBPART == null)

                {

                   var t = env.TABLEMANAGER.getTable("AXMBPART");

                   this.curAXMBPART = t.child(0);

                }

 

             },

 

These force the loading of all static tables. It then keeps a reference to the "current" spare part in the property USERENV.MOBILE.curAXMBPART. This means that anywhere in your scripting you can now reference USERENV.MOBILE.curAXMBPART.PARTNUMBR (the current spare part's number) or USERENV.MOBILE.curAXMBPART.PARTWHOLE (the current spare part's wholesale price). 

 

Note: The USERENV.MOBILE.signOn() function runs because you have previously set this up in your project:

 

 

Log off and restart so that all your changes are loaded. 

 

-------------------------------------------------------------------------------------------------------

Now that we have a table of spare parts available and a reference to the "current" spare part it is easy to show the user what it is and also allow them to change it.

 

Add a group box, a drop down and a label field to your home page, something like this:

 

 

Name the label field SPARE_DETAILS

 

 

Then change its text property to be evaluated by executing this script:  

 

var Text = "No spare part details are available";

var P = USERENV.MOBILE.curAXMBPART;

 

if (P != null)

{

   Text = "NO:" + P.PARTNUMBR;

   Text += ", DESC:" + P.PARTDESC;

   Text += ", STOCK:" + P.PARTAVAIL;

   Text += ", PRICE:$" + P.PARTWHOLE + "(W)$" + P.PARTRETL + "(R)";

}

 

ENV.returnValue = Text;

 

Save your changes.

 

The label field should now start to show details about the current spare part (USERENV.MOBILE.curAXMBPART) in a very "dense" manner – something like this:

 

 

Now change the drop down to have these properties:

 

Property

Value

What does it mean?

dataSourceType

Static Table

Fill from a static table

tableName

AXMBPART

The name of the static table

onFillDropDown

ROW.PARTDESC

Use the spare part description as the visible value in the drop down

onSelectValue

 

ROW == USERENV.MOBILE.curAXMBPART

Select the drop down row if it is the same as the current spare part

onSelectValueChange

 

USERENV.MOBILE.curAXMBPART = ROW;

 

FIELDS("SPARE_DETAILS").refresh();

When the user selects a spare part in the dropdown, change the current spare part reference to the row selected - then ask the "SPARE_DETAILS" label to refresh its own content based on this change.

 

Save your changes.

 

What you should now find is that you can select different spare parts in the drop down and the label area changes to show more details.

 

In effect you have created a very dense spare parts stock and price inquiry screen – using a very simple structure and very small amount of screen real estate (you could of course use multiple labels instead of one large label to present the information in a classical column format).    

 

---------------------------------------------------------------------------------------------------------

 

The concept of the "current" selection passes on to other screens.

 

Display your Customer Details – Meth 1 screen and add a label eXtension like this:

 

 

 

Change the text property of the new label to be dynamically evaluated by this script:

 

var Text = "No spare part details are available";

var P = USERENV.MOBILE.curAXMBPART;

if (P != null) Text = P.PARTNUMBR + "-" + P.PARTDESC;

ENV.returnValue = Text;

 

You should find that the Customer Details – Meth 1 screen displays the details of whatever spare part was selected on the home screen, like this:

 

   

 

---------------------------------------------------------------------------------------------------------

 

You can also use the current selection and dense display approaches to manage searches on much larger data sets.

 

Add this new dynamic SQL table definition to your project:

 

 

   DefineObjectInstance {

      className          = "DynamicTable",

      name               = "AXMBPART-DYNAMIC",  

      source             = "sql",

      selectSQLcommand   = "PARTNUMBR,PARTDESC,PARTAVAIL,PARTWHOLE,PARTRETL,PARTGIFFL from AXESDEMO.AXMBPART where upper(PARTDESC) like '%:SQLVariable_DESC%' ORDER BY PARTDESC ",

      resultColumnNames  = { "PARTNUMBR","PARTDESC","PARTAVAIL","PARTWHOLE","PARTRETL","PARTGIFFL" }     

    };  

 

When executed, this SQL request will produce an aXes table named AXMBPART-DYNAMIC that contains all the spare parts that have a description containing a specified value.

 

Now alter your home screen like this:

 

 

Double check that you have:

·         Named the input field SEARCH_STRING

·         Named the small blank label to the right SEARCH_COUNT

·         Named the drop down SPAREPART_DD

 

Select the "Go" push button to execute this script when clicked:

 

var SearchValue = FIELDS("SEARCH_STRING").getValue().toUpperCase();

if (SearchValue == "")

{

   alert("You need to enter a search value");

}

else

{

   TABLEMANAGER.loadDynamicTable("AXMBPART-DYNAMIC",USERENV.dynamicTablesFile,{SQLVariable_DESC:SearchValue});

   var table = TABLEMANAGER.getTable("AXMBPART-DYNAMIC");

   FIELDS("SEARCH_COUNT").setProperty("text",("Found " + table.childCount().toString()));  

   USERENV.MOBILE.curAXMBPART = table.child(0); 

   FIELDS("SPAREPART_DD").refresh();   

   FIELDS("SPARE_DETAILS").refresh();

   FIELDS("SEARCH_COUNT").refresh(); 

}

 

 

This script:

·         validates what has been input to the SEARCH_STRING field.

·         Executes the "AXMB_PART-DYNAMIC" SQL command defined earlier – substituting the SQLVariable_DESC with the user's SEARCH_STRING value.

·         Updates the SEARCH_COUNT label's text property with a count of how many rows were found by the SQL command.

·         Updates the "current" spare part reference (USERENV.MOBILE.curAXMBPART) to point to the first row of aXes table that the SQL command produced. 

·         Asks the drop down, spare parts details and search count label all to refresh their displays with the updated information.

 

Finally change the static table (yes, static table) source for the drop down SPAREPARTS_DD to be from AXMBPART-DYNAMIC - like this:

 

 

 

Save all your changes.

 

You should find that you can now search by clicking the "Go" button for words like "valve" or "agit" to find various spare part valves and agitators ….

 

 

 

In this simple example you have now managed to produce a generically searchable spare parts stock/cost enquiry – all managed and presented in a very small and dense screen area.

 

Phone, Mail, SMS and Maps Integration

You can integrate with various capabilities of the smart phone.

 

Add these example functions to your USERENV.MOBILE object definition in your projects USERENV.JS file, save the changes and then close/restart as directed:

 

             escape : function(s) { return(encodeURIComponent(s)); }, 

 

             Phone : function(env,number)

             {

                var URL  = "tel:";

                URL += USERENV.MOBILE.escape(number.toString());

                window.open(URL,"_blank");

             },

 

             SMS : function(env,number)

             {

                var URL  = "sms:";

                URL += USERENV.MOBILE.escape(number.toString());

                window.open(URL,"_blank");

              }, 

 

             Mail : function(env,address,subject,body)

             {

                var URL  = "mailto:";

                URL += address;

                URL += "?subject=" + USERENV.MOBILE.escape(subject);

                if ((body != null) && (body != "")) URL += "&body=" + USERENV.MOBILE.escape(body);

                window.open(URL,"_blank");

             },

 

             Map : function(env,address)

             {

                var URL  = "http://maps.google.com/maps?q=";

                URL += USERENV.MOBILE.escape(address);

                window.open(URL,"_blank"); 

             }, /* Watch out for whether you need or don’t need this last comma */

 

 

Now on your Customer Details – Meth 1 screen add 4 buttons towards the bottom of the screen like this:

 

 

Then set up the onClick scripting for each button like this:

 

Button

onClick Script

 

Phone

 

 

 

USERENV.MOBILE.Phone(ENV,USERENV.MOBILE.currentCUSTOMER.CUSTPHONE);

 

Email

 

var MOB = USERENV.MOBILE; 

 

MOB.Mail(ENV,MOB.currentCUSTOMER.CUSTEMAIL,"This is a subject", "This is a message.");

 

 

SMS

 

 

 

USERENV.MOBILE.SMS(ENV,USERENV.MOBILE.currentCUSTOMER.CUSTPHONE);

 

Map

 

var MOB  = USERENV.MOBILE; 

var C    = MOB.currentCUSTOMER;

var Addr = C.CUSTADDR + " " + C.CUSTCITY + " " + C.CUSTZIP;

 

MOB.Map(ENV,Addr);

 

 

The e-mail and map options should work on your PC browser.

 

To test the phone and SMS options you will have to use a real phone or phone emulator.

 

Note:  some Android versions appear to have technical issues with SMS: requests.

 

Forget about using ……..

·         5250 pop-up windows in new smart phone applications (never ever do this).

·         Function key driven applications (there are no function keys on mobile devices).

·         Deep program call stacks. Keep the application flat and simple with simple navigation requests coming from buttons or hyperlinks to move between screens. The more screens that allow you to move directly between them, the easier the application will be to use.

Mostly Forget about using ……..

  • Generally you should not use 5250 subfiles in smart phone applications. There may be valid use – but you should consider alternatives first, especially when selecting business instruments like orders, products, customer, etc.  

 

Using a "Flat" Screen Navigation Model 

In 5250 applications the use of complex program call stacks is common. You log on to Menu A, then option 6 calls up Menu B, where option 2 calls up Menu C, where option 4 calls up the Order Inquiry program. You now have 4 programs all active and in a complex program stack. This is called "stateful programming". In many respects this type of stateful call stack implementation is unique to the IBM i community.

 

In smart phone designs you should try to minimize the use of stateful programming techniques. Such a change is actually very easy to make and will usually produce a simpler and far more flexible and extensible application. Additionally, any programs you produce may be very easily converted into servicing other things (e.g. web services) sometime in the future.

Using a Home Screen 

You should use a single Home screen. Its role is:

  • The screen the user sees initially when they log on.
  • It is the place in which most interactions are initiated from.
  • All other screens should have a button that goes directly back to the home screen. This is something akin to using F12 on a 5250 screen or the Cancel button on a Windows form.

The home screen always has a log off button.

Log off from every screen 

You should have a log off button on every screen.

Using a Messages Screen 

You should use a single Messages screen. Its role is to show status, completion or error message details to the user. Normally it has only two buttons enabled. One to go back to the Home screen (allowing another activity to be initiated) and the other to log off.    

Portrait or Landscape – Choose One            

Generally you should specifically design for Portrait or Landscape mode. In this tutorial all designing is done in Portrait mode. Supporting both modes in your application adds a significant level of complexity. You should assess the effort/reward equation before committing to support both modes.  

Prototyping Your Application

If you have completed the preceding tutorial steps you should have figured out by now that it is quite easy to prototype a smart phone application by chaining together different virtual screens.

 

By adding navigation buttons the basic layout and flow of many different screens can be prototyped, chained together and even demonstrated to stakeholders – even to the point of inserting temporary images onto the screens to demonstrate what the final content (or body) of the application will look like.    

Making a Real Application

When designing and implementing a real application you should never use objects from the AXESDEMO library. Any objects that you intend to use in your application should be copied from source file AXESDEMO/QTUTORIAL and then recompiled with a different object name in a different library. When you change the name of objects you may have to make equivalent changes to copied source code references.        

 

Using the Supplied MS-PowerPoint Set to Draft an Initial Design

 

It is very important that you draft your smart phone application design before you write a single line of code to implement it or physically begin to design any screens with software.

 

This process is called design drafting.  

 

Usually a draft design is reviewed several times with the project stakeholders before you begin to implement it in any form of software.    

 

 

A straightforward and effective way to draft out your proposed application design is by using something like the associated MS-PowerPoint (PPT) set. Alternatively you can possibly buy draft design pads like this from your local computer bookstore.   

 

Copy the shipped Extension_Tutorial 12 - Smart Phone Applications.ppt file from the /docs folder on your aXes server to your PC and then open it. The shipped PPT has the following structure:

 

·         An aXes tutorial identification page - which you can immediately remove.

·         A title page listing the project name, objective, dates of update and versions.

·         A screen summary page that summarizes all the screens in your design

·         Multiple detailed screen layouts – one for each screen in your design

·         A control and image page that contains images you use to produce your design. The shipped version contains some basic details – but you would certainly add to these as your design progresses.            

 

You sketch out your proposed screen designs and make notes about the usage of the screen using one PPT page per screen. Once the design sketch has been reviewed and approved by the project stakeholders, you can begin to implement, possibly by producing a working prototype. The PPTs may act as a simple guiding specification summary – which you might choose to extend either in the PPT set by adding additional pages or by some other means such as MS-Word documents.