App Development: User Guide

Introduction to ZOAPIIO Apps

Apps are end-user web and mobile apps built over ZOAPIIO. App development process is optimized over what you may be used to if you have developed front-end or full-stack apps before.

Let us start by looking at the high-level process.

Conventional approach ...

proceeds roughly as follows -

  1. The project effort and hence teams are divided into one each for the admin app, backend, web app, and mobile app. Besides, there are support teams like devops and QA. If you are using native development for Android and iOS, then you are one more team in your project.
  2. The backend team designs and builds the functional APIs using a suitable server-side language or framework.
  3. The front-end design generally starts with UI wireframes using tools like figma.
  4. The front-end development starts by getting a UI structure generated from the wireframe tool and then proceeds to programming of the interactivity and server integration.
  5. The backend and front-end development proceeds simultaneously as each of these feedback changes into the other.
  6. After a few sprint-cycles the final app starts to take shape and then refined over a period using the same process.

... is sub-optimal

There are several inefficiencies in the conventional approach that ZOAPIIO addresses, such as-
  1. Conventional approach requires multiple and advanced skill sets. These are expensive and suffer for manpower turnover problems.
  2. Multiple teams require coordination - additional time and effort is wasted in managing the touch points.
  3. Larger teams tend to lower the overall productivity.
  4. There is limited opportunity for leveraging code generation. It is mostly limited to CRUD on the server-side and application skeleton on the client side.
  5. The generation benefit is available only once at the start of the project. Enhancements must be programmed manually.
  6. Functionality enhancements impact all teams and turnaround time is high because of interdependencies. Further, the overall timelines are determined by the slowest team.

The ZOAPIIO Way

As we will see in the rest of this document, architecture allows you to break away from convention and adopt a fresh approach addressing most of the pain points. The following are the key characteristics of building apps with -

Getting Started

The process of building web and mobile apps in is the same. This is because the build process relies heavily on code generation. The difference comes when you start to add custom interactivity - for mobile app, you will use the dart programming language and JavaScript for the web. The programming model is identical for web and mobile and only the underlying language is different - you can replicate the same code with only minor changes to syntax.

Creating the app design is easy because uses function first approach. Your design is simply a skeleton for page layout, the appearance is addressed later. To address the web and mobile deployment targes of your app -

  1. You can create the complete design, clone it and then build interactivity for each app independently, or
  2. If your app for web and mobile is identical, then you can build a single app and add Web/mobile interactivity programming separately in the same app.

Before you proceed

Every technology has its strengths and use case scenario where it shines. While is a generic build and runtime environment for internet based solutions for web and mobile, its strengths are best leveraged in a commercial business type of application. Before proceeding, do see the comments below-

  1. A business application is one that has a significant server-side role; there are user transactions, which require monitoring, and perhaps fulfilment and customer service. is ideally suited for this, because it takes an integrated view of the problem and can deliver maximum value.
  2. An application which is heavy on user-interactivity, and has a smaller server-side role, will have limited benefit from the platform.
  3. For applications which have significant server-side role but are also heavy on user interactivity, we advise to use for building the server and server APIs. The front-end should be built using conventional methods (while still using ZOAPIIO services).
  4. The platform offers no advantage to building gaming apps.

Mobile app strategy

The mobile app development landscape today, unfortunately, is fragmented and non-standard. In an ideal world, the web technology, which is already standardized, would work on mobile platforms as well. Bridging solutions exist, but none solves the problem completely - there are trade-offs and choices involved. Before you get down to building the mobile app on ZOAPIIO, take a moment and think about your mobile app needs.

  1. A web-app (written using HTML/JS/CSS) can be compiled for mobile platforms using technologies like Cordova and PhoneGap. However, the resulting application has inferior UI performance compared to the native apps. If your app users are unlikely to be affected by slight drop in performance, this may be the best option. ZOAPIIO Web app can be compiled using Cordova.
  2. PWA is gaining popularity as an alternative to native apps. See if you can drop the mobile app in favor of the PWA. ZOAPIIO supports PWA as well.
  3. Lastly, ZOAPIIO lets you build your mobile app in platform neutral Flutter SDK. This will require more effort and time compared to other options, but you will get native apps for Android and iOS.
  4. You can also consider starting off with a Cordova wrapped mobile app and delaying full graduation to native.

The admin application

A web or mobile app, without an admin control, is of minimal utility. A large part of business functionality consists of provisioning content and policies for the proper functioning of the app. Some common situations are-

  1. Inventory of goods and services sold for an eCommerce app.
  2. Content and advertisements for social media apps.
  3. Management of third-party contracts for content insourced from suppliers.
  4. CRM - managing user complaints and feedback.
  5. Policies - management control on application behaviour.

Think about and document the admin control requirements of your app. You will build the admin application using the Wizard and your database design will be a part of it.

More on Mobile

There are some parts of the mobile app development that need to be addressed outside of ZOAPIIO, in your Cordova or Flutter project.

App environment

Before the app is put on the user's screens, it is required to have properly configured icons for different screen resolutions and configurations. The app may also have a splash screen, a visual to fill the short amount of time it takes before your app opens. You must create these as per the recommended procedure for your environment.

Signing and publishing

Both Google and Apple have a process for listing the app in their on-line stores. They will require you to have an account with them, digitally sign the app and have a verification/review process before the app gets listed on the store. You must go through these steps with the respective vendor.

Versions and dependencies

When building your Cordova or Flutter you may encounter errors depending upon the configuration you have used. You could encounter problem related to versions of your libraries, SDKs and dependencies. You will find solutions to these problems from the Internet search. Most are simple to fix, and you will wise up after some experience.

Accessing device ecosystem

Having an app is a great opportunity to interact with the users' devices and other apps on their device. Both Cordova and Flutter provide means of doing this. You should explore such opportunities and incorporate such features in your app.

Design your app

Consider your application as composed of three functional parts-

  1. The pages in the application, their layout, composition, data source and data binding. WebIDE is an integrated IDE for backend and frontend. This allows you to assign data source APIs and individual data-element bindings at design time. System manages the data retrieval and rendering transparently.
  2. Navigation - a central control to launch pages. System manages the navigation bars and basic navigation in your application. You can, additionally, control the navigation programmatically as well.
  3. Sign-up and registration functionality. You do not treat sign-up and sign-in pages as application pages - this functionality is managed by the system.
app is a collection of pages. Each page is a hierachical composition of views .

Get started by documenting, in plain English or by using a diagramming tool, the list of pages in your application and the layout of each.

The list and the layout of your application pages need not be final right away - start with an essential set - this will evolve during the life of the application. As we have already mentioned, the code generation benefits are available throughout the evolutionary life of your application.

The programming model

will create a functioning flutter or HTML/JS application from the app abstraction that you define. The app is started and managed by the runtime. You will complement the basic app with your custom program stubs for-

  1. User Interactivity. You will need to respond to user actions in the app beyond the standard functionality of the input controls. All of the interactivity handling in the form of responding to events, which you configure with the controls when building the app.
  2. Custom Controls. There may be certain type of input controls that doesn't support out of box. You can provide your own custom controls programmed in HTML/JS and Flutter respectively. Almost all input types are supported natively, so you will require this is advanced cases only.
  3. Styling Overrides. The basic app comes with minimum styling and is designed to support the function. You may want to override the styling of the controls to match your UI style standard.
  4. Other overrides. You can override the entire rendering of a view with your custom HTML/JS or Flutter code respectively. Default rendering is sufficient for most cases, this is an advanced scenario and is rarely needed.
  5. Computational support. If your app requires specialized computational support, the corresponding JS or Flutter libraries can be included in your project.

Your custom program stubs can access and control the contents of the user screen, and app state, among other things. We will look at the details of the programming later, but before we start the discussion on building the application, let us get an overview of the programming interface you will use to achieve this-

The global $.app Object

In both web and mobile app programming, a global object is available to your program stubs named $.app. This is your handle to access anything in the application. Every action you take in the application programmatically will be a method call on this object.

The app Context

The app context is a global object maintained in $.app which can be used to communicate between your application and the runtime. The object itself is a JavaScript object for Web and of the generic object type Map<String,dynamic> in flutter.

Pages, Views, and Elements

hides the details of internal objects and classes; and exposes the abstracted view of the application. The contents of the pages, views, and elements in the app are accessed using their names. When building the apps, remember to give each view/element a simple and recognizable name.

Building your application

From a high-level view, you will build the app following these steps.

  1. Build the admin application. This is the first step because your database is created in this step. This does not require any programming because the Wizard will generate it for you, besides creating the APIs needed for the app registration and sign-in functions in your app. Refer to the Wizard User Guide for details.
If you do not need or want the admin application now (you can always add it later), you will start with the minimal Admin project, which is available in the WebIDE itself. Open the "Mobile app Quick Start" from the "Help" menu. You will find a link to download the Minimal admin app, and instructions on how to deploy it. You can later enhance it for other admin functions.
  1. Write the business APIs. The data that your app uses will be stored on the server and the app will use the APIs to access it. Refer to the WebIDE User Guide for details. This is not mandatory, the data for your app can also be served from canned JSON files stored with the app itself.
  2. Build your app. This is the focus of this guide - the front-end apps.

Steps 2 and 3 above are not strictly separate steps. You will work on these simultaneously and switch back and forth as necessary. Both are a part of the same project and built using the same WebIDE - working on these two steps together is quite natural.

You will build two different projects. The admin application is entirely generated; therefore, we do not add any custom code to it. We will refer to this as the base (or foundation) project. As mentioned before, you can start with the provided Minimal project.

You will build a second project to contain the business APIs and the front-end. Let us call this one as the extension project.
  1. Create a folder on your desktop to hold all project files. The admin app requires a configuration JSON and supporting customization files. Save local copies in this folder.
  2. Your working project is directly deployed on the server, without need for a local save - but it is recommended to locally save the project periodically. Use the same project folder to save this.
  3. It is a good practice to name the second project by adding "-X" suffix (for extension) to the name of the base project.
  4. For ease of database management, define all your tables in the base app configuration - even the ones that do not require admin functionality (entities with type "transaction" are not managed by the admin app).

The WEB-APPLICATION Node

The front-end applications are added to the extension project. Multiple front-end applications can be created in the same project. However, multiple extension projects can be created for each front-end application.

A related node in your schema - APP-COMMONS - contains those parts of your application which are reused across applications. Examples are styles, components and assets.

Start by adding the WEB-APPLICATION node to your schema. Even though the name suggests it is for web apps, but it is used for both web and mobile apps. If your web and mobile apps have similar structure, you can first define a structure and then clone it - this will save you the effort of defining the structure again. Once the basic structure is in place, you can develop the two independently. The structure, for our purpose, consists of-

  1. The pages (APP-PAGE node) and their layout.
    • The layout is specified as a top-down breakdown of the viewable space. The broken-down components in the layout are called views (APP-VIEW node).
    • The lowest level element in the layout, that holds an elementary piece of information is called an Element (APP-ELEMENT node).
  2. The high-level navigation - the one controlled by actions on the navigation bars.
  3. The data binding for each view and element.
    • The data binding also follows a hierarchical breakdown closely mapped with the data structure that feeds data to the view.
    • each view can have its own data source (API) or it can inherit data from its parent view.

Spend some time closely examining the WEB-APPLICATION properties screenshot below. You will define the application-level behaviour and controls here. This also gives you an idea of the amount of work automatically handles for you.

WEB-APPLICATION properties .

Notes:

  1. Your app will have a URL even though it may be a mobile app.
    • During the development stage, the app pages, layout, and navigation can be tested using this URL.
    • This URL serves as the gateway to serve other APIs used in the application or data management.
    • Having a single URL for the entire application helps in hosting the application behind a firewall and the external URL (for web-apps) can be a different convenient name.
  2. You can configure the details of the sign-in module - this is managed by the system. The associated foundation project contains the server-side database and APIs to support this functionality.
  3. The web application can be optionally rendered as PWA, which can also be configured.

Image, Data and HTML assets

Add the image assets in your application using APP-ASSETS under APP-COMMONS, and then APP-IMAGE nodes under that. Make sure the images have appropriate size and resolution for the purpose you intend to use them for. Note that the mobile app (flutter) IDE requires certain app icon images to be provided separately for Android and iOS - these are not a part of the image assets here.

Your project may also require static data files - these should be added as APP-DATA nodes under APP-ASSETS. Only JSON formatted data files are supported, make sure the data is valid JSON - use a validation tool if required.

Your front-end apps can use locally served HTML content (rendered as WebView in Mobile app). Create your HTML content under APP-ASSETS as APP-CONTENT node. The APP-CONTENT can be hierarchical allowing entire web applications to served locally from the app. The WebIDE also allows you a short-cut to import the web app from a ZIP file.

Pages and Layout

You add APP-PAGE nodes under the WEB-APPLICATION, for each page in your app. Leave the sign-in and sign-up pages out because system manages it for you. Include all functional pages, whether launched from the menu nav bars or invoked from app interaction.

Create the layout of each by hierarchically adding APP-VIEW and APP-ELEMENT nodes inside the page. The intermediate views in the page will segment the area into rows, columns or grids and the lowest level views will consist of elements - where you will display the data and accept user inputs. provides a wide selection of element types for different needs.

ZOAPIIO WebIDE has a layout visualizer and editor, but is rudimentary in functionality. It allows you to break down the page hierarchically and view the layout but does not offer detailed controls like a professional design tool you might have seen. It is recommended that you have the layout that you want drawn on a piece of paper when you start.

As you define the page layout, build and then run it on the phone emulator, you may encounter errors from the Flutter layout engine. We have some tips-

  1. Start with a layout that only focusses on dividing the page into views and content for each view. Do not worry about sizing, alignments and scrolling.
  2. Gradually use view options like 'padding', 'detailed style', 'scroll', 'expand', 'center' etc. to improve the presentation.
  3. On a page, use the Scroll option in only one view. The easiest is to use it on the top view only. If you decide to use scroll on an inside view, do not set scrolling for the top view.
  4. For complex scrolling control, get the page to work correctly first, then you can try with adding 'scroll' to multiple views. Revert if something breaks.
  5. Use of 'expand' option is most likely to throw your layout into errors because there are restrictions on its use by Flutter. When you first build your layout, do not use 'expand' at all.
  6. Gradually, add 'expand' option to views and revert if something breaks.
  7. Sometimes, a few trial-and-error cycles are needed in getting the layout right.
  8. In extreme cases, if you cannot get a layout of your desire, you can resort to native Flutter implementation of the view.

Data binding

Your application pages will include data that is supplied from outside - from the server API, for instance. You incorporate this in your pages using Data binding. Server APIs are not the only source of data for your application, it can be canned data provided as a data asset file (JSON) - see APP-DATA, or the app context (in-memory app data).

The page rendering is fundamentally differently for HTML (Web) apps and Flutter (Mobile) apps. tries to create a common model for both, but you should be aware of differences because the underlying implementations are very different. In HTML, an element on the page can be directly referenced and changed and the program has full flexibility in doing so.

Flutter, however, only allows views (Widgets) to be updated from their state data. Data binding is used to implement this behaviour. For your mobile app, any view that you want to dynamically change at run-time (user interactivity), must be bound to a data element (it can be structure). If the data to be bound does not originate from a server API, it can be bound to a local data source.

Data Source, Root and Binding

Routing data to your app pages is controlled through these properties. Data source and root properties are applicable only for a view and binding applies to both views and elements. The rules are as follows:

  1. All data sources (API, canned, or app context) used in your app must declare their structure in the project schema.
  2. When defining the data source a view, you must identify the node in the schema that contains the definition of the source structure. This is essential, otherwise cannot manage the data inside the page.
  3. A view can have its own data source or it can be bound to a sub-structure from its parent.
  4. Multiple data sources can be a part of the same page.
  5. Data source or binding is not mandatory for a view. For instance, a view may not require any external data.
  6. If a view does not explicitly binds itself to a source or parent's data sub-structure, it inherits the same binding as its parent.
  7. If bound, a view must be bound to an object in the source - it cannot be an elementary data item.
  8. Elements can have bindings for its value, label, help and herotag properties. Each can be a fixed literal value or a binding to an elementary item in its parent's view.

As noted before - the app context is a simple hash, mapping names to values (possibly objects). Data source property can reference data from the app context. Please note that you must programmatically populate the app context with correct values before pages containing the referenced data is called. Data source can take one of the following forms-

  1. A name in format appcontext:name. The name is looked up in the app context and that value (which should an object) is used as source.
  2. A name starting with http:, or https:. It is taken to an external API which is called to fetch the source.
  3. A name starting with /. It is taken to a service API and is called to fetch the source.
  4. Any other name. It is taken to be the name of a data asset (See APP-DATA) in the project, the contents of which are used as the source.

Additionally, with an API URL, app contenxt substitutions can be used to include parameters to the API using the {{}} notation. E.g. http://host.com/products/{{productid}}, where productid is picked up from the app context and substituted for {{productid}}, before calling the API.

App navigation

In app, you can have a default navigation plan for the app and you can optionally override it for each page. The navigation plan consists of buttons that will appear on the navigation bars located at the top and/or bottom of the user screen.

You add "APP-NAVIGATION" tag to your application and on pages where you need a different navigation. Within that you add the list of commands and the location of the command button. The button can be positioned on the navigation bar itself (left or right) or on the dropdown menu that is launched from one of the navigation bars. There is great deal of flexibility on how you decide to structure the navigation controls. A command can be placed on both the top and bottom bar, if required. The dropdown menus themselves are available on both the nav bars.

You can attach one of the following actions with each command in the navigation -

  1. Transition to another named page.
  2. Launch the named page as a modal popup with a close button. This can be used to display alerts and information messages.
  3. Login/Logout function. The label for this button is automatically set based on the current logged in status of the user. The command then allows the user to login or logout.
  4. Programmed handling. In this case, the system does not take any action and you must handle the event programmatically. See events.

Data routing

manages data inputs from the user and automatically makes it available to the API services that are bound to the views. System also automatically renders the views from the API output based on the data bindings.

  1. All input fields on a page are captured as a flat set of "Name-Value" tuples.
  2. These values are passed as standard POST HTTP parameters to the API calls in the page that is invoked from the page.
  3. This works when the page invocation is automatic (in response to a Submit) or programmatic from custom code provided by you.

Server-driven UI

This is a relatively new trend in mobile app development to deal with the challenges associated with pushing your app to your existing users.

  1. With every push to the play store, there is a publishing process that can take a few days.
  2. Even after the app is in the play store, it can take many days - even weeks - before the app is updated for all users. You will have to deal with your users running different versions of your app.
  3. The problem gets further compounded with bugs in your app. If a buggy update gets into circulation, it could take many days before it can be flushed out via an update. This could even affect your business.

In Server-driven mobile UI, you push the description of the page composition via an API from the server, and the app uses that description to render itself.

Building Server-driven mobile UI is a breeze with . No extra steps are required, you simply flag parts of your application that you want server-driven and manages the rest. Pages, views, assets, and even navigation commands can be flagged for server rendering. There are some rules, though-

  1. You can flag an entire page as Server-driven. This allows you to add completely new pages to your app on-the-fly. There is a caveat here, though. The page cannot have any Flutter/dart code in it, for instance, to handle custom interactivity. The reason is obvious - the flutter code needs to be compiled into the app and cannot be pushed dynamically.
  2. If a page was static when it was pushed to the play store, you can still override it by changing to Server-driven.
  3. In pages that are not Server-driven, you can flag specific views to be Server-driven. The advantage of this is that you can have Flutter/dart code that is pushed along with the page to the app, but the content, layout, rendering can be altered on-the-fly.
  4. App Assets can also be flagged as Server-driven - such assets are not baked into the app, are fetched by the app dynamically.
  5. App Navigation commands can also be flagged as Server-driven. You can add additional commands to the navbars, and override existing ones using this. Please note that adding a command of type "Programmed" requires a handler to be present in your app.

User interactivity

Besides the App navigation, the users will interact with the app by clicking/tapping on elements on the page. In HTML and JavaScript, event handlers can be attached to elements even after they are created. In Flutter, however, the event handler must be provided at the time of creating the element. provides a common model for Web and Mobile apps for letting users interact with your app. This is done through events. The $.app object that we have seen before, manages these events.

Event routing

The 'fire' and 'listen' methods are used for this. When you define an element on the page (WebIDE), you also mention the events you are interested in, from that element. Then you can take action when these events occur.

  1. For elements of type 'button', the event 'pressed' is implied and is same for both web and mobile apps (for consistency) - you do not need to mention it in your list.
  2. For element of type 'submit', the event 'submit' is fired and handled within the system. The default submit behaviour is to validate the form and if there are no validation errors, the control is passed to the next page along with all the form fields.
  3. If you want a different behaviour - such as additional validations - use the type 'button' and listen to the 'pressed' event.

The data that is passed at the time of 'fire' is passed to handler mentioned in the 'listen'. Normally, you will not need to fire the events in your program because the system does it automatically based on the events that you have mentioned in the element definition. The event names are the ones that HTML uses - E.g., click, doubleclick, mousever etc. These names are also same for both web and mobile for consistency - internal implementation will use the appropriate equivalent.

You may use the 'fire' function if you require custom events. There is no restriction on the names of the events, you can use your own custom event names and trigger/handle them programmatically.

Function Web App (JS/jQuery) Mobile App (Dart/Flutter)
The global UI object $.app $.app
Listen to an event $.app.listen(eventname, pagename, elementname, handler) $.app.listen(eventname, pagename, elementname, handler);
Trigger (fire) an event $.app.fire(eventname, pagename, elementname, handler, data) $.app.fire(eventname, pagename, elementname, handler, data);
Event processing in front-end.

Event handling

As already mentioned, you handle events though the listen function of the $.app object. An event is uniquely identified as the combination of event name, the page name, and the element name. It is important to note that only one listener can be attached to an event. If you attempt to attach another listener (I.e. call the listen on the same event), the previous one is removed.

So, where should be listening code be placed? For web apps, there is only one place, which is the PAGE-SCRIPT attached to the page. For web apps, although you can override the view layout with HTML code, no JavaScript can be placed there. You must put all listen commands in the PAGE-SCRIPT, there is one for every page.

For mobile apps, you can override the view layout using Flutter code. Besides overriding the _buildWidget method, you can also add initState method to the widget. You can add other widget lifecycle methods there too. The body of the initState method is the right place to listen to events and handle them.

Updating the user view

Updating the user view is simple and straight forward in HTML/JavaScript/jQuery. You can reference any element by its Id, Class or Name attribute and modify its content.

For Mobile apps, rebuild method of $.app object is used. You will recall from our earlier discussion that any view that you need to programmatically update must be bound to some data (server API or local data asset). This is because Flutter requires that data to be a part of the Widget state.

Dart is a strongly typed language, although you can use untyped variables and structures. The use of strong typing allows for error detection at the time of compilation and leaves you more confident that the code will not blow up at runtime - though the chances are that it still will, for other reasons. takes advantage of the strong typing feature and generates data classes for you based on the data schema you have provided. When a view is rendered, an object of the mapped data class is passed to it - it is not a generic Dart map, but object of a class.

If you are updating a view, you must update this object before the rebuild, otherwise the view will remain unchanged because the underlying data will remain same. The state data for the Widget corresponding to the view can be updated by providing an object of Dart Map<String,dynamic> type. This object should only contain the changes to the original object, which itself was created from the JSON data from its source.

The last parameter to the fire method is this object. The changes from this object are first applied to the state object and then the rebuild of the view is performed. You should examine the generated data classes to know what fields are present in the object.

An example of the rebuild usage is given below -

$.app.listen('click', 'CALCULATOR', 'CBUTTON', (var w) {
	print('CBUTTON Click');
	Text t=w as Text;
	Calculator calc=$.app.state['calc'] as Calculator;
	String val=t.data ?? '';
	var result=calc.key(val);
	$.app.fire('rebuild', 'CALCULATOR', 'CALCTOP', {'value': result});
});
	

Manipulating the page view

The views and elements on your app pages get their behaviour and looks from the configuration you provide in the WebIDE. Certain default behaviour is applied to the input elements.

  1. When user interacts with these elements, events are dispatched for you to action them in your program.
  2. When navigating between pages, the values entered by the user on a page is made available to the API services on the next page.

At times you may want to modify the configuration of the input element when handing user interactivity. E.g. you may want to disable input on a field based on some condition, or may want to alter the look (display properties like style, size, label etc.) at run time. You may also want to change the data displayed on the page in response of some event.

You will use the rebuild method of the $.app object for this. See the $.app Object reference for details.

Mobile app examples-

// Disable input on Element
$.app.rebuild('page-name', 'element-name', {'inputdisabled': true});

// Set counter (property in the bound object) to 2.
$.app.rebuild('page-name', 'view-name', {'counter': 2});

// Increment counter by 1 - by passing patchdata as a function.
$.app.rebuild('page-name', 'view-name', (viewdata) { viewdata['counter']++; });
	

Web app example-

// Disable input on Element. element is the DOM node.
$.app.rebuild(element, {'inputdisabled': true});
	

Styling the app

uses a function first development approach. This means that when developing the app, you will focus on getting the functionality and page content hierarchy right. The final rendering for web and mobile will require a complex set of functions provided by jQuery/Bulma CSS and Flutter respectively. does not attempt to abstract the fine nuances of application aesthetics. Chances are that the application that you get as the first output will be only nice looking. The formatting controls in WebIDE are designed to make the application look presentable, which may or may not be the final desired presentation.

There is where you will use the custom view layout feature.

allows you to override the underlying HTML/Flutter code for rendering at view level. You must source the skills of professional app designers to get your app to look good. Entry-level Flutter/HTML skills are needed to incorporate the Custom layouts in your app.

  1. Typically, you will override the rendering at the lowest (leaf) level view.
  2. You should look at the HTML/Flutter code that has been generated by the system first. Then clone it and apply changes.
  3. The generated code will also show you what structure is bound to the view and how to access its sub-elements when creating your custom rendition.

$.app Object reference

Web app (JS) WIP

$.app method Return Type Parameters Description
fire Fire an event




getAppContext




getData Fetch the data from an URL




listen Register a listener for an event




loadPage Transition to the named page




patchAppContext Update the app context




popupPage Open the named page as a popup (dialog)
$.app JS reference (INCOMPLETE)

Mobile app (Flutter)

$.app method Return Type Parameters Description
fire void String eventtype,
String pagename,
String target,
dynamic data
Fire an event. Event names are generic and the apps can use any arbitrary name. System fires some fixed event (E.g. nav, pressed, click, rebuild). Apps can fire system events also. The target of the event is identified by the pagename and the target (View or Element). Finally, with the event arbitrary data can be passed which is delivered to the listen handler.




formdata String? String pagename,
String target,
String value

Set/Get the values in form data. Form data is data that will be sent to the server when the page is submitted.

When an input element on the page is changed, this value is updated immediately. If you are writing a custom component, you should make this call to update the form data when its value changes.

target is the name of the element and value is the new value. To query the value, pass null for the value.





getAppContext dynamic String name
Get an entry from the app context




getData Future String url,
Map<String,dynamic>? postdata,
Map<String,String>? headers,
Fetch the data from an URL. postdata and headers are optional and named parameters. The method returns a Future<dynamic> object. When the future completes, it resolves to the data received from the API.




listen void String type,
String pagename,
String target,
void Function(dynamic) handler

Register a listener for an event. You must specify the event name and identify the sending element/view through the pagename and target (which can be view name or element name). For 'nav' events, the pagename is always blank and the target name is the name of the nav command.

The handler receives as parameter an object whose type depends on the event being handled. If the event target is a view, the parameter is of type UIView and if the target is an element, the parameter is of type UIElement. (See Helper classes below).





loadPage void UIPage? currentpage,
String pagename,
bool replace,
Map<String,dynamic>? patchcontext,
Map<String,dynamic>? patchformdata

Transition to the named page. If 'replace' is true, the loaded page replaces the top of page stack (See Flutter documentation). Otherwise, it is added on top of the page stack.

This call requires a handle to current page from where you are making this call. This is available to your programs as 'widget.page'. 'pagename' is the name of the page to load.

Last two parameters are optional and named. They respectively contain any changes you want to make to the app context and the formdata being submitted, before loading the page.





patchAppContext void Map<String,dynamic>? patchdata
Update the app context. App context is a global Hash map, preserved across pages. This allows you to pass information between pages. The data bound to app views can also reference elements from it. Updated are applied while retaining the unchanged entries.




popupPage void UIPage? currentpage,
String pagename,
Map<String,dynamic>? patchcontext,
Map<String,dynamic>? patchformdata
Works like 'loadPage', except the page is opened as a popup.




rebuild void

Rebuild a view or an element with changes. The rebuild method works differently for views and elements, described separately below.





rebuild (View) void String pagename,
String viewname,
dynamic patchdata

For the view, the patchdata contains updates to the data object that is bound with the view. It can be a Function which receives the current bound object as parameter and it returns the updated object. Alternatively, it can be an object containing values to be updated. Only values present in the patchdata are updated, others remain unchanged.

Also for the view, the nested views are also automatically updated to reflect the data changes.





rebuild (Element) void String pagename,
String elementname,
dynamic patchdata

For the element, the patchdata contains updates to the element properties - it cannot be a Function. The properties that can be updated are the following and the new property values are in the same format that you provide in the WebIDE, when configuring the element. See Helper Class UIElement for the list of properties.

Example (Page Flutter code)-

void init() {
	// CBUTTON and CALCVAL are elements.
	$.app.state['calc'] = Calculator();
	$.app.listen('pressed', 'CALCULATOR', 'CBUTTON', (var w) {
		print('CBUTTON Click');
		UIElement t=w as UIElement;
		Calculator calc=$.app.state['calc'] as Calculator;
		String val=t.prop('label') ?? '';
		var result=calc.key(val);
		$.app.rebuild('CALCULATOR', 'CALCVAL', {'value': result});
	});
}
	
$.app Flutter reference

Helper Class UIView

UIView is the internal implementation of the View. A reference of the object is passed to the handler listening to events on the View. The handler can query the properties of the view using the prop method.

Method Return Type Parameters Description
prop dynamic String name

Query a property of the view. The following is the list of properties and their respective data types.

  1. events: String,
  2. layout: String,
  3. center: bool,
  4. scroll: bool,
  5. safearea: bool,
  6. expand: bool,
  7. reversetabs: bool,
  8. padding: String,
  9. label: String,
  10. displaystyle: String,
  11. displaysize: String,
  12. displayicon: String,
  13. width: int,
  14. widthispct: bool,
  15. data: UIData

Helper Class UIElement

UIElement is the internal implementation of the Element. A reference of the object is passed to the handler listening to events on the Element. The handler can query the properties of the view using the prop method.

Method Return Type Parameters Description
prop dynamic String name

Query a property of the view. The following is the list of properties and their respective data types.

  1. addonicon: String
  2. addonlabel: String
  3. addonside: String
  4. addonstyle: String
  5. addontype: String
  6. events: String
  7. displayalign: String
  8. displaysize: String
  9. displaystyle: String
  10. displaywidth: int
  11. displaywidthispct: bool
  12. help: String
  13. inputrequired: bool
  14. inputdisabled: bool
  15. label: String
  16. padding: String
  17. selectoptions: String
  18. validationregex: String
  19. value: String

Helper Class UIData

UIData is the internal implementation of Data structure associated with a View. A reference to the view data can be obtained by querying the data property.

Method Return Type Parameters Description
resolveValue dynamic String? name

Query a value from the data. If a name is provided the vaue of the named property in data is returned, and if the name is null, the entire data associated with the view is returned as a dynamic hash.


Push notifications

apps have pre-configured push messaging capability using Firebase Cloud Messaging (FCM) - the messaging platform from Google. You will need to -

  1. Create a project on Firebase,
  2. Add apps to the project (for each mobile app),
  3. Acquire the keys and configuration files, and
  4. Finally, add the keys/configuration to your ZOAPIIO project.
    • The Server key should be copied to your Web App properties in WebIDE.
    • The Configuration files should be added to your Mobile project - the configuration for Cordova and Flutter are different.

Please refer to the documentation on Firebase and Cordova/Flutter configuration for the same.

Once your app is compiled and ready, you can send push notifications to the logged in B2C users, from the Admin console of the Base (foundation) Project. To send push notifications from your application (Server APIs), compose a JSON object with following structure -

	{
		"to": "<the Id of the user from the b2cuser entity in your base project>",
		"notification": {
			"title": "The title of the notification message",
			"body": "The text of the notification message"
		}
	}
	

Then, serialize it into a string, and send to the provided MQ destination as text. The following Biz rule in your WebIDE will accomplish this-

	JmsSend to Destination FCMPUSH-QUEUE /Path/to/MessageNode@_JSON
	

Launching the Web App

The web app is served from the container. This is the most efficient way to render the web app because the instance also holds all your services and data.

It is easy to launch the web app. Simply right click on the WEB-APPLICATION node in your WebIDE, and click on "Launch Application". You can also launch it by directly typing its URL in the browser. The app URL is constructed from your instance URL, the app URL and finally appending '/index' to it.

Native Mobile (Flutter) App

Running and testing your mobile app requires you to setup the Flutter development environment on your machine. Flutter is supported on multiple IDEs - most popular being the Android Studio, and Visual Code. You will need to acquire some basic Flutter knowledge - there are several Internet resources available that will get you started very quickly. Pick an IDE and that you are comfortable with and install the flutter environment. WebIDE will generate the Flutter source code, which you must copy into an empty Flutter project shell.

  1. Install the Flutter environment and create a new project.
  2. From the ZOAPIIO WebIDE, under the Tools menu, select the "Generate Flutter Project" command.
  3. Select the application (WEB-APPLICATION) that you want to generate and pick a server URL. When generating the Flutter app that will run with a different ZOAPIIO server, you should change the server URL - default value points to your development server.
  4. If all goes well, a ZIP file will be downloaded to your machine. Open it and you will find three folders - assets, images and lib. Copy these folders to your Flutter project folder (use the File Explorer to copy the files).
  5. Use your IDEs build, test, run and package commands to work with your mobile app.
  1. Use can use either a Mac or a Windows machine, but to be able to test the iOS build of your app, you are required to have a Mac for your development machine.
  2. Also, all mobile development environments (even before Flutter) are resource hungry. The same is true of Flutter - you need a development machine of a recent vintage.
  3. In the Flutter project, there is a special file called 'pubspec.yaml' which controls the project environment and external dependencies.
  4. Make sure the images and assets folders are exposed as project assets.
  5. assets:
    - images/
    - assets/
    		
  6. Also add the dependencies. The following is an example, your requirements may differ-
  7. dependencies:
    	cupertino_icons: ^1.0.3
    	event_bus: ^2.0.0
    	google_fonts: ^3.0.1
    
    dev_dependencies:
    	flutter_test:
    		sdk: flutter
    
    	http: ^0.13.3
    	flutter_spinkit: ^5.1.0
    	event_bus: ^2.0.0
    	device_info_plus: ^3.2.3
    	shared_preferences: any
    	animated_text_kit: ^4.2.1
    	geolocator: ^8.0.5
    	google_sign_in: ^5.3.2
    	flutter_facebook_auth: ^4.3.4
    	firebase_core: ^1.17.1
    	firebase_messaging: ^11.4.1
    	material_design_icons_flutter: ^5.0.6295
    	flutter_form_builder: 7.2.1
    	expressions: ^0.2.3
    	table_sticky_headers: ^2.0.0
    	flutter_inappwebview: ^5.4.3+7
    	flutter_titled_container: ^1.0.7
    	video_player: ^2.4.7
    	flick_video_player: ^0.5.0
    	visibility_detector: ^0.3.3
    	url_launcher: ^6.1.6
    		
  8. For Android build of the Flutter project, another file called 'AndriodManifest.xml' comes into the picture.
  9. Make sure the AndriodManifest.xml file grants access to the app to networking and other services by adding the following.
  10. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    	package="com.XXXX.YYY">
    	<uses-permission android:name="android.permission.INTERNET"/>
    	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    
    	<application...
    		
  11. iOS build will have a similar environment specific control file.

Cordova Mobile App

Cordova is an open-source cross-platform mobile app development platform. Biggest plus in its favour is that you can take an existing web application and compile it for mobile - both Android and iOS. Only requirement is that your web app must be responsive, so that it renders well on the mobile screen.

Cordova mobile apps are not native apps, however. makes building Flutter apps very easy, but it is still not as direct as using Cordova. Depending upon the complexity of user interaction in your app, your target user profile and your development budget, you can decide your entry to the mobile app market. If you are not sure, we suggest you start with the Cordova app because it is faster to build and progressively advance to the native flutter app. Both are cross-platform.

Running and testing your Cordova mobile app requires you to setup the Cordova development environment on your machine. No IDE is required - it is mostly command line, but you can use an IDE, if you already have one. WebIDE will download the web app source code (HTML/CSS/JS) as bundle, which you must copy into an empty Cordova project shell.

  1. Install the Cordova environment and create a new project.
  2. From the ZOAPIIO WebIDE, under the Tools menu, select the "Generate Cordova Project" command.
  3. Select the application (WEB-APPLICATION) that you want to generate and pick a server URL. When generating the Flutter app that will run with a different ZOAPIIO server, you should change the server URL - default value points to your development server.
  4. If all goes well, a ZIP file will be downloaded to your machine. Open it and you will find the www folder. Copy the contents of this folder to the www folder of your Cordova app.
  5. That is all you need, just build your Cordova project and run.
  6. If you need to change the URL of the server for the app, you will find this in the index.html file, simply change the URL and rebuild. You can have different build for testing and production.

Reference Guide

Summary

Legend: Web App Only w. Mobile app only m.

Tag Description
WEB-APPLICATION The complete abstraction of your Web or Mobile app.
APP-CUSTOM m Place to put your non-UI related Dart classes - business functions or computational logic.
APP-FLUTTER m Place to put overrides for mobile app default styling.
APP-SPLASHPAGE m A page to display welcome animation or graphics before the first page.
APP-NAVIGATION App level navigation plan.
APP-NAVCOMMAND A specific command in the navigation plan
APP-PAGE Pages in your app.
APP-VIEW The content of the page is organized into views.
APP-VIEW Views can be nested.
APP-ELEMENT Leaf level content element that renders a piece of information or input control.
APPVIEW-FLUTTER m Provide custom rendering for mobile app.
APPVIEW-HTML w Provide custom rendering for web app.
APPVIEW-WEBVIEW Indicates that the view is an embedded web app. If present, other tags are ignored.
PAGE-FLUTTER m Page level code to handle interactivity and override of styling.
PAGE-SCRIPT w Page level code to handle interactivity.
APP-NAVIGATION Navigation plan specific to the page.
APP-NAVCOMMAND Individual navigation command in the plan.


APP-COMMONS The parts of your app, which are shared across multiple apps - both web and mobile.
APP-META w Put all your meta tags here that you want in the web app home page.
APP-STYLE Put all your css code here to style the web app.
APPVIEW-STYLE A specific command in the navigation plan
APP-COMPONENT Define a custom component (Element) to augment the standard element set.
APPC-FLUTTER m Flutter implementation of the custom component.
APPC-JAVASCRIPT w Web implementation of the custom component.
APP-ASSETS Assets for your web or mobile app.
APP-DATA Canned JSON data.
APP-IMAGE Image
APP-CONTENT Local Web content (HTML/JS/CSS) that you want to embed in your app.
APP-CONTENT App content can be nested.
Organization of Web app Tags.

WEB-APPLICATION

"WEB-APPLICATION" is where you will define your application - web as well as mobile. In a project, you can have multiple applications.

Attribute Description
URL Path The application must have a URL, even if it is a mobile application. The URL must start with '/wa', so the system knows it represents an application. System uses a prefix convention. You will recall that HTTP services need to start with '/wc/' etc.


Target Many Tags and properties in your WEB-APPLICATION hierarchy are applicable only to Web or Mobile apps. If your app is targeting only the web or the mobile, you can say so here. This will keep the inapplicable Tags and properties hidden and simplify your interface. Options are - web, mobile, and web&mobile.


Mnemonic Name This is for internal use. Give a short name without any special characters in it.


Market Name This is the brand name of your application. Give a short name, that your application will be known as to its customers.


Opening Page This is the page which will be displayed when the application opens. Select a name from one of the pages you will add to your application. If a splash page has been defined (mobile app only), it will be shown after the splash page. You will need to come back and update this property after you have added pages to your app.


Description Textual description for the purpose of documentation.


Login Type ZOAPIIO has login services for b2b and b2c type users. B2B users are added by the administrator, while the B2C users can subscribe themselves. Presently, this should be set to 'b2c' - b2b sign-up from apps is not supported.


Session Scope The system uses JWT for transmitting authenticated user information. You may build multiple apps running on the same ZOAPIIO container. So that their authentication scope is independent from one another, provide a unique value here.


Login Text The text you want to use for the login - E.g. 'Sign-In', or 'Login', etc.


Logout Text The text you want to use for the logout - E.g. 'Sign-Out', or 'Logout', etc.


Register Text The text you want to use for registration - E.g. 'Sign-Up', or 'Register', etc.


Foundation Project

The WebIDE is an integrated development environment for front-end and backend. The service APIs for login administration are a part of the Admin app - automatically generated by the Wizard. If your application has no admin functionality, use the built-in Minimal base project. From your WebIDE, follow instructions to Mobile app Quick Start,

Provide the name of foundation (or base or admin) project here.



Require Username Should the user be asked to pick a username at the time of registration.


Require Email Should the user be asked to provide her Email Id at the time of registration. Possible values are - 'yes', 'no', and 'with verification' (this will require the user to verify the email before registration).


Require Phone Should the user be asked to provide her Phone No at the time of registration. Possible values are - 'yes', 'no', and 'with verification' (this will require the user to verify the phone number through an OTP before registration).


Text/Email Sender Service

When selecting 'with verification', you must write a service to handle the actual delivery of the OTP to the user via email and/or phone. You should then, provide the URL of the service here.

The service will accept two inputs - the token and the destination phone/email. The service can determine the destination from the content (@ in the text implying email). The URL that you provide should have 2 placeholders for each value - #D (destination), and #T (token). The service should create the message text and then send it to the phone or email as applicable. The registration module will substitute the values and call this URL.



Additional Registration Fields If you want any additional fields at the time of registration, provide a comma separated list here. Only Age and Gender are supported at this time. These fields should also be declared in b2cuser table of the base app.


Google Maps API Key If you are planning to use Google Maps in your application. Google Map support is planned in future.


Facebook App Code If you are planning to allow Facebook login to the users, provide the facebook app code here. This is also a planned feature.


Enable PWA Select it you want to allow your web application to be run as PWA.


PWA Properties (multiple) Enter PWA related properties here.


VAPID Keys When using notifications to the PWA in chrome-based systems, a VAPID key is required. You do not need to enter it; the designer allows you to generate the keys on the fly.
Attributes of the "WEB-APPLICATION" Tag.

APP-ASSETS

"APP-ASSETS" is used to input your application assets - Images and Data files. Create your assets under this tag. There are no attributes for this tag. For web application, the assets are bound to the URL asset/{asset-name}. For mobile app, the assets are reproduced in the generated folder under subfolders "assets", and "images" respectively. The data assets can be used as data source when binding to the app views.


APP-COMMONS

"APP-COMMONS" is used to aggregate together all parts of your app, which can be shared across multiple apps and between web and mobile apps.

APP-CUSTOM

"APP-CUSTOM" is applicable for mobile application only. You can include any custom classes that your application requires, here. The code here is replicated in the generated Flutter project as 'custom.dart' and is automatically imported in all other generated dart files.

A sample script is given below. This implements a simple calculator class. For instance, if your application was implementing a calculator, you can add the computation logic here and keep your UI code clean and structured.

import 'package:expressions/expressions.dart';

class Calculator {
	String val = '0';

	String key(String keytext) {
		if (keytext == 'C') return (val = '0');
		if (keytext == '=' || keytext == '+-') {
			try {
				Expression expr = Expression.parse(val);
				const evaluator = ExpressionEvaluator();
				var result = evaluator.eval(expr, {});
				if (keytext == '+-') result *= 1;
				val = result.toString();
			} catch (err) {
				return val;
			}
		} else if (keytext == '()') {
			if (val == '0' || val == '') return (val = '(');
			var last = val.substring(val.length - 1);
			if (last.compareTo('0') >= 0 && last.compareTo('9') <= 0) {
				val += ')';
			} else if (last != '(') {
				val += '(';
			}
		} else {
			val += keytext;
		}
		return val;
	}
}
	

Attribute Description
Name The name of the script. Even though there is only one custom tag in your entire application, you should give a valid name.


Type This must be set to Dart because the mobile app uses Dart.


Description Textual description for the purpose of documentation.
Attributes of the "APP-CUSTOM" Tag.

APP-COMPONENT

Attribute Description
Name The name of the component. You will add it to your app pages as Element with type custom:COMPONENT-NAME. Provide the Web and/or Mobile implementation of the component by adding APPC-JAVASCRIPT and APPC-FLUTTER Tags under it.
Attributes of the "APP-COMPONENT" Tag.

APP-CONTENT

APP-CONTENT is used to define lightweight HTML content in the app itself. APPVIEW-WEBVIEW Tag in the app structure is used to embed it into the app pages. For Mobile, this is packed into the app itself - so do not define heavy content here.

APP-CONTENT Tag can be nested, allowing complete directory structure of your web application to be captured. Typically even the simplest web content has separate CSS and JS folders, but there can be more. WebIDE also has a short-cut tool to import the APP-CONTENT from a ZIP file.

Attribute Description
Name The name of the asset - this can be any name not necessarily the name of the file.


Server Driven You can designate any asset to be Server-driven. For details, see Server-driven UI.


Content Type This value must be content type (MIME type) or folder if this is a folder in the app content structure.


Base64 Encoded Any binary content in your app must be Base64 Encoded and then this flag checked, so that system knows to decode it before use. Typically, you will use this for images, which are binary files. When using the ZIP import utility, the Base64 codification is automatically handled.


Relative Path

This must be the actual name of the folder or the file on disk. Your HTML content will have embedded reference to other files - so that these runtime references remain valid.

Please note that additional setting changes are required to the pubspec.yaml file in Flutter. Every asset folder needs explicit declaration.



Description Textual description for documentation purposes.
Attributes of the "APP-CONTENT" Tag.

APP-DATA

"APP-DATA" tag is used to embed fixed static data in your application. It can be associated as data source with a view in your application (data source is normally a service API URL).

Right-click on the tag to launch the editor, where you can type of paste your JSON text. Example-

{
	"Name": "World",
	"Count": 1
}

Attribute Description
Name The name of the DATA asset


Server Driven You can designate any asset to be Server-driven. For details, see Server-driven UI.


Type This value must be set to Json, because that is the only format being supported at this time.


Description Textual description for documentation purposes.
Attributes of the "APP-DATA" Tag.

APP-ELEMENT

"APP-ELEMENT"s represent the data display/input elements on the page (both web and mobile).

Attribute Description
Name The name of the element - it is required because your programs will use the name to reference the element.


Description Textual description for documentation purposes.


Type The element type, valid values are-
  1. label - Display some text.
  2. text - This is same as label but allows you to style each differently by overriding in your code.
  3. input - A simple user input field.
  4. textarea - a longer multi-line text input field.
  5. password - like input, but the typed text is not displayed.
  6. username - like input, with decoration/validation rules for a username.
  7. email - like input, with decoration/validation of an email.
  8. tel - like input, with decoration/validation of a telephone number.
  9. number - numeric input field.
  10. date - date input field.
  11. select - a dropdown input field. (See Options attribute below).
  12. button - an action button, to be handled programmatically.
  13. submit - an action button to automatically submit the current page.
  14. checkbox - a checkbox input field.
  15. radio - a radio input field.
  16. image - displays an image.
  17. video - plays a video.
  18. hidden - a hidden input field.
  19. custom:COMPONENT-NAME - A custom component (should be declared in your app).


Options (If select) If the element type is 'select' or 'radio', provide the options separated by commas here.


Value (Binding) A fixed string or data element to be bound to this element - select from the options provided.


Events Certain events are emitted by default, others must be explicitly requested by naming them here. 'button' elements emit 'pressed' event and other input elements emit 'change' event by default. If you want other events, mention comma separated list here. Possible values - click, doubleclick, mouseover.


Style This value is based on Bulma styling options. Select one from the list. An approximate equivalent style is provided for mobile elements.


Size This is also based on Bulma values, and an approximate equivalent is chosen for mobile elements.


Text Align The alignment for the field - select from the list.


Icon (Material Design) Enter the name of an icon from Material Design library to be used with the element.


Label (Binding) The text to display for label, button and submit element types. Binding can be used in place of fixed text.


Help Message (Binding) For input elements, you can specify a short help text here. Binding can be used in place of fixed text.


Field Add On Both Bulma and Flutter allow you to create a combination input element where a button can be attached to the input field. You can apply an add on to the element, choose the position here - before or after.


Add On Type Add-on type can be button, submit or static. If button is specified, clicking/tapping the button will fire the 'addon' event from the element. If submit is specified, submit action is automatically performed.


Add On Label (Binding) Label for the add-on, can be a binding.


Add On Style Style for the add-on - select from list.


Add On Icon (Material Design) Enter the name of an icon from Material Design library if the add-on should be displayed with an icon. Both Web and Flutter apps use the Material Design icons set.


Input Required This is for validation of input fields - should an input be mandated on this field.


Input Disabled Should the input on the field be disabled?


Validation (regex) Provide a regular expression if the input value needs additional validation.


Html Id The Html Id - it will be reproduced as the id property of the generated HTML tag. This property has no effect for mobile app elements.


Html Class The Html Class - it is reproduced as the class property of the generated Html tag. You can provide multiple class names (space separated). The class name list can include Bulma class names or your custom class names (add corresponding style for the class under APP-STYLE tag. This property has no effect for mobile app elements.
Attributes of the "APP-ELEMENT" Tag.

APP-FLUTTER

You can override application level formatting defaults here.

// Supply your implementation of following functions for a stylename and optionally elementtype.

// Foreground color
Color foreground(String stylename, {String? elementtype})

// Background color
Color background(String stylename, {String? elementtype})

// Font size
double fontsize(String sizename, {String? elementtype})

// Text style
TextStyle? textstyle(String stylename, {String? elementtype})

// Button Style
ButtonStyle? buttonstyle(String stylename, String sizename, {String? elementtype})

// Override how a title is displayed for a view.
Widget applyViewTitle(Widget w, String title)
		

Attribute Description
Type This must be set to Dart.


Description Textual description for documentation purposes.
Attributes of the "APP-FLUTTER" Tag.

APP-IMAGE

"APP-IMAGE" represents an image asset.

Attribute Description
Name The name of the image. It is referenced in the application by name. For web application the image is bound to the url "asset/{name}".


Server Driven You can designate any asset to be Server-driven. For details, see Server-driven UI.


Image The image itself, upload from your local disk.


Description Textual description for documentation purposes.
Attributes of the "APP-IMAGE" Tag.

APP-META

"APP-META" tag is relevant for web applications only. You can place HTML meta tags here - these are reproduced in the application home page. You can have multiple APPP-META tags, for each app you must name the one you want to use. Example-

<title>Sample App</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
		

Attribute Description
Name A name. This is required and your app must reference the APP-META to be used using this name.


Type This must be set to Html because the contents are HTML


Description Textual description of the purpose of documentation.
Attributes of the "APP-META" Tag.

APP-NAVCOMMAND

"APP-NAVCOMMAND" represents a command button to be placed on one of the navigation bars in the app.

Attribute Description
Name The name of the command, it is a required attribute.


Server Driven You can designate a nav command to be Server-driven. For details, see Server-driven UI.


Html Id The Html Id - it will be reproduced as the id property of the generated HTML tag. This property has no effect for mobile app elements.


Html Class The Html Class - it is reproduced as the class property of the generated Html tag. You can provide multiple class names (space separated). The class name list can include Bulma class names or your custom class names (add corresponding style for the class under APP-STYLE tag. This property has no effect for mobile app elements.


On Top Navbar Where should it appear on the top bar - none, left, right or menu.


On Bottom Navbar Where should it appear on the bottom bar - none, left, right or menu.


Label The label for the command button.


Icon (Material Design) Enter the name of an icon from Material Design library if the button should be displayed with an icon. Both Web and Flutter apps use the Material Design icons set.


Action Type of action to be performed when the command is invoked - possible values are Load Page, Popup Page, Login/Logout, or Programmed. When Programmed is selected, system does not take any action. In the page script of your opening (home) page, you should listen to the "nav" event with blank pagename and target Command-Name, and handle it programmatically.


Action Target If the Action is set to "Load Page" or "Popup Page", you should specify the name of the page here.


Description Textual description for the purpose documentation.
Attributes of the "APP-NAVCOMMAND" Tag.

APP-NAVIGATION

"APP-NAVIGATION" is used to define the application navigation. Both web and mobile apps can have up to two navbars (top and bottom) - both are optional. APP-NAVIGATION is defined at the application level, but it can be overridden for specific pages. When overriding, the entire Navigation must be defined again. It is not possible to override certain parts of the default navigation.

Usually, the top navigation bar also has a logo. For web applications, the navigation bars can be fixed or floating - floating bars scroll with the page and do not remain fixed on the screen. For mobile applications, if you choose to have a navbar, it must be fixed.

Attribute Description
Name The name for convenience. The name itself has no significance.


Logo The Logo to be used in the top navbar, if present. The logo itself must be added as an image asset, and then named here.


Top Navbar The nature of the top navbar - possible values are none, floating, or fixed.


Bottom Navbar The nature of bottom navbar - possible values are none, floating, or fixed.


Description Textual description of the purpose of documentation.
Attributes of the "APP-NAVIGATION" Tag.

APP-PAGE

"APP-PAGE" represents a page in the application - both, web and mobile. Add each page in your application here and configure the layout of each. The sign-up and registration are automatically managed by the system, and you should not define pages related to sign-in and sign-up.

With each page, you can say if a login is required to access the page. If you set this property to true for the homepage, then your application will force a login/sign-up before entry. Generally, you want to have a generic welcome page for all users and force login for functional pages.

Attribute Description
Name The name of the page. The pages are referenced by name.


Server Driven

You can designate a page as Server-driven by flick of a switch - rest of the page definition remains same. Once so marked, the app need not be generated/compiled and pushed to the app store. Once deployed, the changes take effect immediately.

A page marked as Server-driven cannot have any flutter/dart code in it for handling interactivity. The page works with default behaviour in terms of navigation and flow. ZOAPIIO offers considerable flexibility for handling such situations - see Server-driven UI.



Label The page will usually have a human readable label, which is displayed with the page.



Next Page 's navigation system automatically handles submit buttons on the page. All the input fields in the page are put in a name-value tuple connection and then the control is passed to the page that is named here. If this if left blank, the control is sent to itself (current page). You can, of course, not have any submit buttons on the page and handle button clicks programmatically.


Require Login Check this box, if the use cannot access the page, until she has registered and logged in.


Description Textual description of the purpose of documentation.
Attributes of the "APP-PAGE" Tag.

APP-SPLASHPAGE

"APP-SPLASHPAGE" is applicable only for mobile apps and it not the same as what flutter calls the splash page. Flutter allows you to provide a splash page, which is shown for the fraction of a second it takes to load the application. If you require that, handle it in flutter.

This splash page is more like a flash page which can be flashed to the user as an introduction or some animation to enhance the app looks. The duration of flash is selectable, and typically should not be more than 2 seconds.

If you choose to have this flash page, you must provide the implementation as the _buildWidget method as shown in the example below-

Widget _buildWidget($LoginData? d) {
	return Image.asset('images/SPLASH.gif');
}

Attribute Description
Name The name of the page, it should be present.


Show Logo A very basic flash page is generated by the system, which is just a placeholder, until your build your own. Check this if you want the logo to be a part of the placeholder flash page.


Duration (ms) For how long, the flash page should be displayed.


Fetch Location If you plan to use the geo-location of the user in the flash page, check this box - before rendering the page, geolocation will be retrieved and passed to the render routine. If the user has logged in in the past, her details are also retrieved and passed to the flash routine.


Description Textual description for the purpose of documentation.
Attributes of the "APP-SPLASHPAGE" Tag.

APP-STYLE

"APP-STYLE" is CSS code that you write to providing styling information for the web application. It if ignored for mobile apps. When defining views and elements, you can add class names to the HTML elements that get generated. You can apply styling to elements using the class names.

web apps use Bulma styling framework. For styling, try to use Bulma classed where possible and add your own, only when necessary.

Attribute Description
Name The name of the style set. Although there is only one per application, the name is still required.


Type This must be set to Css.


Description Textual description for the purpose of documentation.
Attributes of the "APP-STYLE" Tag.

APP-VIEW

"APP-VIEW" nodes are the building blocks of the page layout. You start breaking the page down from top into views. At the lowest level are APP-ELEMENT nodes.

Attribute Description
Name The name of the view - it is required because your programs will use the name to reference the view.


Server Driven

You can designate a specific view as Server-driven simply by flick of a switch. If a page or a view is flagged as Server-driven, all contents below this are also server driven.

For details, see Server-driven UI.



Description Textual description for the purpose of documentation.


Layout How the contents of the view should be arranged. Possible values are-
  1. block - No specific layout is applied. Content is rendered in sequence. Use this if you are implementing your own rendering of the view.
  2. tabs - The views appearing directly under this are rendered using a tabbing control. A tab bar is shown allowing the user to switch tabs. Only one view in the nesting hierarchy is displayed at a time. The Label attribute contains the tab label.
  3. grid - A contents (next level of views) are rendered as a grid. The number of columns in the grid is determined by the width setting.
  4. column - The contents are laid out as a column.
  5. row - The contents are laid out as a row.
  6. field-row - this is a special layout for web apps only to render input elements in a row. The content of this view should be input elements.
  7. header - unused.
  8. footer - unused.


Desired Width The desired width of the view. It can be expressed as a plain number, or a number followed by a %.


Container Layout This property comes into picture when rendering a list (the view is bound to an array item). This layout is applied to the outer container that will house the list items. Possible values-
  1. free - No specific layout is applied. Content is rendered in sequence.
  2. grid - A contents (list items) are rendered as a grid. The number of columns in the grid is determined by the width setting.
  3. column - The list items are laid out as a column.
  4. row - The list items are laid out as a row.
  5. table - The list items are laid out as a table.


Data Source

The data source for the view. It can be left blank if there is no external data in the view or the binding of parent view should be used. You can type either the name of a local data asset or the URL of a ZOAPIIO service.

You can also drag and drop the nodes from the application schema representing the ENTRY-POINT or APP-DATA.

Source for the view can also be pointed to an in-memory data structure saved in Application Context. The app context can be accessed from your program and you can put the data programmatically before the view is called to render. Use appcontext:app-context-entry-name, to use this feature.



Data Source Root The structure of the data that will be received from the data source needs to be declared in your project schema. Provide the path of the node in your schema that contains the definition of the structure.


Data Binding Type the path of the data element relative to the data source assignment to which this view is bound or has inherited from its parent.


Events You can trap and handle user events at view level. Mention comma separated list here. Possible values - click, doubleclick, mouseover.


Label The label for your view.


Icon (Material Design) Enter the name of an icon from Material Design library if the tab label should be displayed with an icon. Both Web and Flutter apps use the Material Design icons set.


Style Font style to display the label. This value is based on Bulma styling options. Select one from the list.


Size The font size to display the label. This value is based on Bulma styling options. Select one from the list.


Padding Specify the padding to be applied to the view here. Enter 1, 2 or 4 numeric values separated by space. The values sets are - single uniform padding, vertical and horizontal symmetric padding, or individual settings for top, right, bottom and left.


Center Check this box if you want the content to be centred.


Scroll This is applicable only for the mobile app and check this box if you want the contents of the view to be scrollable.


Html Id The Html Id - it will be reproduced as the id property of the generated HTML tag. This property has no effect for mobile app elements.


Html Class The Html Class - it is reproduced as the class property of the generated Html tag. You can provide multiple class names (space separated). The class name list can include Bulma class names or your custom class names (add corresponding style for the class under APP-STYLE tag. This property has no effect for mobile app elements.
Attributes of the "APP-VIEW" Tag.

PAGE-SCRIPT

"PAGE-SCRIPT" is applicable for web application only. This is a JavaScript program, that you associate with each page to manage the user interactivity. For mobile apps, dart/flutter code can be associated with each view, because of the nature of its design. For web applications, this is the only place where you can place your code. You can and should have one script for each page in the web application.

A sample script is given below. Your program will mostly listen to system generated events and take action.

$.app.listen('beforeload', 'HOMEPAGE', '', function(data) {
	console.log ('HOMEPAGE LOADING..');
});
$.app.listen('onload', 'HOMEPAGE', '', function(data) {
	console.log ('HOMEPAGE LOADED');
});
$.app.listen('change', 'HOMEPAGE', 'Department', function(data) {
	console.log ('Department Changed');
});
$.app.listen('click', 'HOMEPAGE', 'Department', function(data) {
	console.log ('Department Clicked');
});

Attribute Description
Name The name of the script. Even though there is only one script in the page, you must give a valid name, the system uses this name to access it.


Type This must be set to JavaScript because only JavaScript is supported at this time.


Description Textual description for the purpose of documentation.
Attributes of the "PAGE-SCRIPT" Tag.

PAGE-FLUTTER

"PAGE-FLUTTER" is applicable for mobile apps only. This is a Dart/Flutter program, that you associate with each page to -

  1. Manage the user interactivity. Put this inside the body of a "void init()" function declaration.
  2. Override styling defaults for the page. All methods available for override in APP-FLUTTER are available here.
  3. Optionally, provide implementation of the _buildPage(BuildContext context) method, if you want to take control of rendering the page. This is useful if you want a completely native Flutter page. Remember to check the appropriate box in Tag properties, if you use this feature.

A sample program is given below. Your program will mostly listen to system generated events and take action.

void init() {
	log('PAGE INITIALIZED');
	$.app.listen('click', 'HOMEPAGE', 'TREATMENT-SMALLCARD', (target) {
		UIView view=target as UIView;
		UIData data=view.config['data'] as UIData;
		var sourcedata=data.source;
		$.app.patchAppContext({'treatment': sourcedata});
		$.app.loadPage(this, 'DETAIL-TREATMENT', false);
	});
	$.app.listen('nav', '', 'SAYHELLO', (dynamic target) {
		UIPage page=target as UIPage;
		print('SAYHELLO FIRED');
		$.app.popupPage(page, 'HELLO-POPUP');
	});
}
Color color(String style, {String? elementtype}) => Colors.green;

Attribute Description
Type This must be set to Dart.


Override _buildPage Checkbox, to be checked, if you are providing an alternate implementation of the _buildPage method.


Description Textual description for the purpose of documentation.
Attributes of the "PAGE-FLUTTER" Tag.

APPC-JAVASCRIPT

APPC-JAVASCRIPT is the Web implementation of the Component. The implementation is done by providing an anonymous class. The constructor of the class receives an element object, which provides access to the element properties defined with APP-ELEMENT tag. The class has following methods in it.

  1. render(clsnames): This method will generate and return HTML string that renders the component.
  2. activate(): This method will be called when the element is activated. You can add interactivity to the element here.
  3. value(newval): This method will be called to set or get the value of the Element. This method should apply the value change, if provided and return the current value inputted by the user.
  4. validate(): This method is called when the page is submitted to validate the user input. It should return the error string or blank if there is no error.
  5. validationError(errorstr): This method is called to display the error to the user. The method should display the error and return the errorstr back.

Example-

class {
	constructor(element) { this.element=element; }
	// Return the HTML string or object {html: string, cls: string, attrs: hash}
	render(clsnames) {
		var data=this.element.config('value') || {};
		var prods=data.ProdItem || [];
		var treats=data.TreatItem || [];
		var ret='<div class="table-container">\n';
		ret+='<table class="table has-sticky-header has-sticky-footer has-sticky-column">\n';
		ret+='<thead><tr>';
		ret+='<th>Name</th>';
		ret+='<th>Quantity</th>';
		ret+='</tr></thead>\n';
		ret+='<tbody>';
		ret+='<tr><th colspan=2>Products</th></tr>';
		for (var i in prods) {
			ret+='<tr>';
			ret+='<th>'+prods[i].ProductName+'</th>';
			ret+='<td>'+prods[i].Quantity+'</td>';
			ret+='</tr>';
		}
		ret+='<tr><th colspan=2>Treatments</th></tr>';
		for (var i in treats) {
			ret+='<tr>';
			ret+='<th>'+treats[i].DiseaseName+'</th>';
			ret+='<td>'+treats[i].Quantity+'</td>';
			ret+='</tr>';
		}
		ret+='</tbody></table></div>';
		return ret;
	}
	// The component is rendered, add interactivity to it
	activate() {
	}
	// Get or Set the value of the component
	value(newval) {
	}
	// Validate the state - return error string or blank for no error
	validate() {
	}
	// Display the error and return it
	validationError(errorstr) {
	}
}

Attribute Description
Type This must be set to JavaScript.
Attributes of the "APPC-JAVASCRIPT" Tag.

APPC-FLUTTER

APPC-FLUTTER is the Mobile implementation of the Component. The implementation is done by providing a Flutter Widget class definition. The class declaration should incorporate "with UIElementMixin" to inherit functions that will allow you to access the element properties.

  1. The Widget constructor will receive two parameters - of type UIPage and String, which should be saved as instance variables in UIElementMixin, as shown in the example below.
  2. Property config of type Map<String,dynamic> inherited from UIElementMixin lets you access the properties defined with APP-ELEMENT.

Example-

// Structure of the Flutter component
class SHOPCART_DTL extends StatefulWidget with UIElementMixin {
	SHOPCART_DTL(UIPage page, String name) { this.page=page; this.name=name; }
	SHOPCART_DTLState createState() => SHOPCART_DTLState(config);
}

class SHOPCART_DTLState extends State<SHOPCART_DTL> {
	Map<String,dynamic> _config;
	SHOPCART_DTLState(this._config);
	@override
	void initState() {
		super.initState();
	}
	@override
	Widget build(BuildContext context) {
		// Build your widget here. The value
		return Text('@TODO SHOPCART_DTL');
	}
}

Attribute Description
Type This must be set to Dart.
Attributes of the "APPC-FLUTTER" Tag.

APPVIEW-FLUTTER

"APPVIEW-FLUTTER" allows you to override the default rendering behaviour in the mobile application. The rendering in flutter works in a different way than that way it is done in HTML. For mobile app, each view is converted to a Dart class (which itself extends the Flutter Widget). Typically, you will require custom rendering for the bottommost views in your page. The flutter rendering is quite complex and cannot abstract every nuance of the rendering for you. It is best to use system generated page layout and then provide custom code for each leaf view in the page.

Before your start writing a customization, spend some time studying the class that the system generates by default. An example is produced below.

class HOMEPAGE$HOME_VIEW extends StatefulWidget {
	String name='HOME-VIEW';
	UIPage page;
	$Null? pdata;
	HOMEPAGE$HOME_VIEW(this.page, $Null? d) { if (d != null) pdata=d; }

	@override
	HOMEPAGE$HOME_VIEWState createState() => HOMEPAGE$HOME_VIEWState(pdata);
}
class HOMEPAGE$HOME_VIEWState extends State<HOMEPAGE$HOME_VIEW> {
	// Source is '', Binding is '';
	$Null? pdata;
	$Null? data;
	InAppWebViewController? webview;
	bool isLoading=true;
	HOMEPAGE$HOME_VIEWState(this.pdata) { _setData(pdata); }
	@override
	void initState() {
		super.initState();
		$.app.listen('rebuild', 'HOMEPAGE', 'HOME-VIEW', (d) { if (mounted) {
			setState(() {});
			rebuildChildren();
			}; });
		$.app.listen('rebuild', 'HOMEPAGE', '', (d) { if (mounted) {
			setState(() {});
			rebuildChildren();
			}; });
	}

	void rebuildChildren() {
		$.app.fire('rebuild', 'HOMEPAGE', 'INFOGRAPHIC', null);
		$.app.fire('rebuild', 'HOMEPAGE', 'HOME-TREATMENTS', null);
		$.app.fire('rebuild', 'HOMEPAGE', 'HOME-PRODUCTS', null);
	}

	Widget _buildWidget($Null? d, BuildContext context) {
		return _defaultWidget(d, context);
	}
	// APP-VIEW - HOME-VIEW
	Widget _defaultWidget($Null? d, BuildContext context) {
		return UIView(widget.page, widget.name)
			.data(data)
			.styleOptions('','black','','')
			.scroll()
			.sizeOptions(0,false)
			.layout('Column')
			.addChild(_childWidget0(d, context))
			.addChild(_childWidget1(d, context))
			.addChild(_childWidget2(d, context))
			;
	}
	Widget _childWidget0($Null? d, BuildContext context) {
		return HOMEPAGE$HOME_VIEW$INFOGRAPHIC(widget.page, null);
	}
	Widget _childWidget1($Null? d, BuildContext context) {
		return HOMEPAGE$HOME_VIEW$HOME_TREATMENTS(widget.page, null);
	}
	Widget _childWidget2($Null? d, BuildContext context) {
		return HOMEPAGE$HOME_VIEW$HOME_PRODUCTS(widget.page, null);
	}
	void _setData($Null? d) { pdata = d; data = pdata; }
	Widget _builder(BuildContext context) {
		return _buildWidget(data, context);
	}
	Widget _builderWithData($Null? d, BuildContext context) {
		_setData(d); return _builder(context);
	}

	@override
	Widget build(BuildContext context) {
		Widget ret = _builder(context);
		return ret;
	}
}

Attribute Description
Override _buildWidget Checkbox, to be checked, if you are providing an alternate implementation of the _buildWidget method.
Attributes of the "APPVIEW-FLUTTER" Tag.

APPVIEW-HTML

"APPVIEW-HTML" allows you to override the default rendering behaviour in the Web application. You can provide your own HTML that will be used, and all other nested Views and Elements are ignored. When using custom HTML, the layout value should be set to block and the view must not be a repeating view (bound to array). You would need to add another view under the repeating view, if you want to provide a custom HTML for it.

When taking ownership of the view, you need a mechanism to access the data that is bound to the view so it can be included it in your custom HTML. This is done using the tag attributes that you put in the custom HTML. data-databind attribute can contain the path of a data element (same syntax as the Data Binding property in the designer) - this tells the system that a data element is bound to the element. data-bindtgt attribute is where you tell where the element value should go -

  1. 'html' means the value would be inserted as the inner HTML of the element,
  2. 'val' means that value of the element is replaced,
  3. Any other value means the attribute with that name is where the value will be inserted. For instance, to bind an image tag to its URL, this should be 'href'.
  4. Examine the default HTML generated by the system (Use your browser's debugging tools for this) as guide in writing the override HTML.

APPVIEW-STYLE

"APPVIEW-STYLE" represents a detailed styling representation that can be attached to an APP-VIEW. The styling is generic in nature and it can be used for both mobile and web apps. This allows you to create styles that can be reused not just across multiple webapps but also between web and mobile apps.

For web applications, additional or as an alternative, custom styling can be provided as CSS with the APP-STYLE node. The CSS, however, has no effect on the mobile app rendering.

Attribute Description
Name The name, it is required and is used to refer to the style.


Background Color This is specified in HTML (#RRGGBB) notation and a helper control is available to select the color. The value can also be manually typed.


Padding The padding is the amount of space to be added inside the area being styled between its edges and the content. A smart input control allows you to input the specification in Uniform, Symmetrical, or Individual formats. Please note that the suffix px, usually used with CSS is not entered and is assumed. Because we are using a generic minimal styling, specifying the values as a percentage is not supported at this time.


Margin The margin is the amount of space to be added around the area being styled. The format and restrictions are same as for Padding above.


Border The border is the border specification for the area being styled. The format and restrictions are same as for Padding above.


Border Color The color of the border in HTML (#RRGGBB) notation.


Border Radius You can pick rounded borders for the the area being styled. The format and restrictions are same as for Padding above. This setting is only effective if a uniform border (same width for all edges) has been selected. For other formats of border selections, this setting has no effect.
Attributes of the "APPVIEW-STYLE" Tag.

APPVIEW-WEBVIEW

Attribute Description
Name The name, it is required.


Target URL The URL of the application to open in the webview. The URL can be external - starting with https:, http:, or data:. Other URL values are assumed to be local web apps and should be declared under APP-ASSETS -> APP-CONTENT.
Attributes of the "PAGE-FLUTTER" Tag.