Tutorial for application development
In this section, we will show you how to develop a simple application on the IBAX Network.
The Goal
The application begins with simple functions but grows in complexity as the tutorial progresses.
In the final version of the application, some simple messages (strings) are stored in a database table, which contains the timestamps and account identifiers of senders. Users can view the messages list and add a new message from the application page which can be accessed from the menu of the ecosystem.
Part 1: The Environment
Weaver
As the only client of IBAX, Weaver provides functions for all users and ecosystem roles. With it. Application developers can develop and test their applications, ecosystem administrators can manage their ecosystems, while users can interact with the ecosystems.
In this tutorial, you are going to code contracts, page templates and perform all other actions in Weaver. Weaver also provides a way to restore, save and execute contract codes, manage data structures (database tables), assign access permissions and create applications.
Each node has its own Weaver instance.
Part 2: Contract
Your first simple application is "Hello, World!".
> In this application, strings will be stored in a database table, and there is not a user page.
Creator account
Accounts with the Developer role will be assigned the "root" privileges of the ecosystem. By default, this role can access all actions. In a new ecosystem, the creator account will be assigned the Admin role, which you must use it to introduce major changes to the ecosystem, such as creating new applications and database tables.
Log in to the ecosystem using the creator account.
New application
Once you logged in as the ecosystem creator, you can create a new application.
Create a new application:
Go to the Developer tab;
Select Application in the menu at the left;
Select New at the application page;
Specify the application name in the APP field;
Set Conditions to
true
;
true
means anyone can make changes to the application;Another option is
ContractConditions("MainCondition")
, which means no one can make changes to the application except for the creator.Your application will be displayed in the applications list, click the Name field of a specific application to activate it.
You can access relevant resources by clicking an application in the Developer tab, no impact on the ecosystem.
No matter which one you choose, all ecosystem applications are still available.
New database table
To store the data, create a database table for the application in Weaver.
Create a data table:
In the Developer tab, select Application > APP > Database table;
All database tables in relation to the application selected will be displayed here. If the list is empty, then, no database tables have been created for your application yet.
Click New;
Weaver will show you the page to create a new database table.
Specify the name in the Name field;
In this tutorial, the name of the database table will be
apptable
.Add the
message
column, set its type asText
;This table must have two columns:
id
(predefine) andmessage
. You are going to add more columns later.
With respect to the read and write permissions, set each field to
true
;This will allow anyone to insert, update entries, add columns and read entry data on the database table;
As an option, you may reserve the read and write permissions to the creator account. In this case, set this field to
ContractConditions("MainCondition")
.
New contract
Contract code
Each contract has three parts. For more details, please see: Contract structure.
Create a contract
-
In the Developer tab, select Application > APP > Contract;
All contracts in relation to the application will be displayed here. The list is empty for new applications.
-
Click New;
A new contract template will be displayed in the editor.
An empty contract template is shown as below:
contract ... {
data {
}
conditions {
}
action {
}
}
Contract name
First, please specify the contract name.
contract AppContract {
}
Data
Fill in the data
section.
In the following example, Message
refers to the variable name, while string
the variable type.
data {
Message string
}
Conditions
Fill in the conditions
section. A simple verification condition is to avoid
empty strings. If the length of Message
is 0
, a predefined warning message
will be triggered when implementing the contract.
conditions {
// avoid writing empty strings
if Size($Message) == 0 {
error "Message is empty"
}
}
Action
Fill in the action
section. A simple action is to write Message
into the
data table.
action {
DBInsert("apptable", {message: $Message})
}
Full contract code
The full contract code is shown below.
All contracts in IBAX will be constructed like this, including the data
,
conditions
and action
sections.
contract AppContract {
data {
Message string
}
conditions {
// avoid writing empty strings
if Size($Message) == 0 {
error "Message is empty"
}
}
action {
DBInsert("apptable", {message: $Message})
}
}
Save and run
Now, we are preparing to test the contract:
Click Save in the editor's menu;
This will update the contract code, and the updated version will be available to all network nodes.
Click Run in the editor's menu;
This will display the Run the Contract page.
In the Run the Contract page, fill in the input parameters of the contract;
As this contract has one parameter
Message
, setMessage
at the Key field andHello, World
at the Value field.Click Run.
The result will be displayed at the right.
If successfully added some strings, then, the result will contain the block ID and result code to introduce the change of transactions.
{
"block": "31",
"result": null
}
Part 3: Page
When the contract becomes effective, it is time to extend it to something useful. In this part, you are going to implement the UI and other functions.
In this application, strings will be stored in a database table, like entries in a log. Each string will have an author and timestamp.
Users can view the list of strings stored at the application page, which is shown as a simple form then.
New field
As with the previous, edit the database table at the Developer tab > Application > APP > Database table page;
Add the following fields into apptable
:
author
, field typeNumber
, set Change totrue
;
This field will store the identifier of the author account.
timestamp
, field typeDate/Time
, set Change totrue
.
Update the contract
We will update the contract code to handle the author ID and timestamp.
The author ID is the account ID of the ecosystem. The timestamp is the date and time executing the contract in Unix time format.
As both values are provided by the Predefined variables and no need to input or verify the predefined variables, they can only be updated in the action part.
Update the contract to write the author ID and timestamp into the database table
when adding a message, among which the author ID is defined by $key_id
, while
the timestamp by $time
.
action {
DBInsert("apptable", {message: $Message, author: $key_id, timestamp: $time})
}
Page
For the application page, it is a simple page where displays the messages stored in the database table.
Like all other resources, you can create the UI page in Weaver:
-
Navigate to the Developer tab, click Application > APP > Page;
-
Click New;
The visual designer will be opened in a new tab.
Designer views
The default page is empty. You can use the predefine structure to quickly fill in the page.
Create a basic table:
-
In the view selector at the right, click Designer;
The view will be switched to the visual designer.
-
In the menu at the left, select Table With Header and drag it on to the page.
A table with multiple elements will be displayed on the page.
Developer view
As the user page of IBAX is coded with a Template Language, please switch to the Developer view when writing the page code.
Switch to the Developer view.
-
In the view selector at the right, click Developer.
The view will be switched to the editor with a tab holding the page code.
Fetch data from the database table
So far, nothing done with the page template. In the next, we will update the
code to allow the page to display data from apptable
.
-
To request data from the database table with the DBFind function;
In the following example, this function call is used to fetch data from
apptable
. The data will be put it in the sourcesrc_table
and sorted by the timestamp field.src_table
will be later used as the data source for the page in table view.DBFind(Name: apptable, Source: src_table).Columns(Columns: "author,timestamp,message").Order(timestamp)
-
To display the data from
src_table
, specify it as the data source and the header in theTable
function.Table(Columns: "AUTHOR=author,TIME=timestamp,MESSAGE=message", Source: src_table)
-
In the view selector at the right, click Preview to check whether the data is displayed correctly.
Full page code
The following is the full page code for this part. This basic page will be expanded later.
DBFind(Name: apptable, Source: src_table).Columns(Columns: "author,timestamp,message").Order(timestamp)
Div(Class: panel panel-primary) {
Div(Class: panel-heading, Body: Table block)
Table(Columns: "AUTHOR=author,TIME=timestamp,MESSAGE=message", Source: src_table)
Div(Class: panel-footer text-right) {
Button(Class: btn btn-primary, Contract: ContractName, Body: More)
}
}
Save the page
Click Save to save the page:
- Specify
AppPage
or any other name for the page in the Page Name field; - Select
default_menu
in the Menu; - Set Conditions to
true
; - Click OK.
Part 4: Application
In the previous sections, you created a contract, a table to store data, and a basic UI page to display that data.
In this part, you are going to finalize the application to make its appearance and actions are similar to an actual one.
Menu
The page needs to be linked to a menu, for example, default_page
displayed on
the Home tab is linked to the default ecosystem menu default_menu
.
As this application tutorial is very simple (only having one page), there is no need to create a separate menu for it. The new menu item in the default menu is sufficient.
You can define the page menu by editing the page properties at the Developer tab > Application > APP > Page. For example, if your app has multiple pages, you may need to create a menu to navigate between these pages and assign it to all pages of the app.
Add a menu item
Like all other resources, menus can be created and edited in Weaver:
-
Navigate to the Developer tab > Menu;
-
Click the Name of the
default_menu
entry;A new tab will be opened in the editor.
-
Add a new menu item to the end of the template, which will be linked to open the application page and its icon comes from the FontAwesome icon set.
MenuItem(Title:Messages, Page:AppPage, Icon:"fa fa-envelope")
-
Click Save.
Test the new menu item
Check whether the new menu item is valid:
-
Open the Home tab;
-
Click Refresh in the menu;
An entry with a header of Messages will appear;
-
Click Messages.
The application page will be opened.
Send a message
The buttons in Logicor can be used to implement contracts and open pages, depending on the parameters. The Button function has two contract parameters:
-
Contract
Name of the contract activated.
-
Params
Input parameters of the contract.
Form
To send data to the contract, add a form on the application page, which must have an input field for a message and a button to activate the contract AppContract.
The following is an example of this type of form. It is nested in its own
Div. Putting it after the Div element that
contains the form view, which defines that the
Input field has a predefine name
message_input
. The button uses this name to send the value of Message
to the
contract. Finally, the Val function
is used to get the value of the input field.
Div(Class: panel panel-primary) {
Form() {
Input(Name: message_input, Class: form-control, Type: text, Placeholder: "Write a message...", )
Button(Class: btn btn-primary, Body: Send, Contract: AppContract, Params: "Message=Val(message_input)")
}
}
You may notice that when testing this new feature by sending a message, the form does not refresh. This will be introduced in page refresh.
Form navigation
Under the default view, the form on the page can only display 25 entries on the first page. Hence, you can add some simple buttons to navigate users to all form entries.
Navigation buttons
There will be two navigation buttons, and each of them could reload the application page and pass the parameters to it.
- The Previous button will display the first 25 entries. If there are no other entries, the button will not be displayed;
- The Next button will display the next 25 entries. If there are no other entries, the button will not be displayed.
Variables
The navigation buttons require two variables to store the table view states:
#table_view_offset#
This variable stores the offset of current table view. The navigation buttons will pass it as a parameter when the page is reloaded.
#record_count#
This variable stores the total number of entries in the table. The value will be calculated.
Entry count
To count #record_count#
, please modify the existing
DBFind function call. The variable specified in
the .count()
call will store the entry count.
DBFind(Name: apptable, Source: src_table).Columns(Columns: "author,timestamp,message").Order(timestamp).Count(record_count)
Table offset
The table view offset must be passed to the page when the page is opened. If
#table_view_offset#
does not get a value, set it to 0.
Add the following code to the top of the page.
If(GetVar(table_view_offset)){
}.Else{
SetVar(table_view_offset, 0)
}
Modify the DBFind function call again. This time it must use the new table view offset.
DBFind(Name: apptable, Source: src_table).Columns(Columns: "author,timestamp,message").Order(timestamp).Count(record_count).Offset(#table_view_offset#)
Button code
Find the Div function call that defines the
footer: Div(Class:panel-footer text-right)
. Add the button code into it.
Div(Class: panel-footer text-right) {
}
The Previous button will only appear if there is at least one Next to return.
When adding a button, the new table view offset offset_previous
of the page
will be calculated. The parameters are passed to PageParams
of the reopened
page.
If(#table_view_offset# >= 25) {
SetVar(offset_previous, Calculate(#table_view_offset# - 25))
Button(Class: btn btn-primary, Body: Previous, Page: AppPage, PageParams:"table_view_offset=#offset_previous#")
}
The Next button will only be displayed when the total number of records is
greater than the number displayed on the page. When a button is added, the new
table view offset offset_next
of the page will be calculated. The parameters
are passed to PageParams
of the reopened page.
If(#record_count# >= Calculate(#table_view_offset# + 25)) {
SetVar(offset_next, Calculate(#table_view_offset# + 25))
Button(Class: btn btn-primary, Body: Next, Page: AppPage, PageParams:"table_view_offset=#offset_next#")
}
After adding these buttons, save the page and test it from the Home > Messages menu item.
Page refreshing
The last function to be implemented is to automatically update the table on the page. When users send a new message, it must be displayed in the table.
In addition to implementing the contract, you may also use the Send button to
reopen the current page to achieve the same. #table_view_offset#
must be
passed to the page without any change.
Add Page
and PageParams
to the Send button, the code is as follows:
Button(Class: btn btn-primary, Body: Send, Contract: AppContract, Params: "Message=Val(message_input)", Page:AppPage, PageParams:"table_view_offset=#table_view_offset#")
Full page code
This part describes many changes to the application page. The following is the full code of the application page.
If(GetVar(table_view_offset)){
}.Else{
SetVar(table_view_offset, 0)
}
DBFind(Name: apptable, Source: src_table).Columns(Columns: "author,timestamp,message").Order(timestamp).Count(record_count).Offset(#table_view_offset#)
Div(Class: panel panel-primary) {
Div(Class: panel-heading, Body: Table block)
Table(Columns: "AUTHOR=author,TIME=timestamp,MESSAGE=message", Source: src_table)
Div(Class: panel-footer text-right) {
If(#table_view_offset# >= 25) {
SetVar(offset_previous, Calculate(#table_view_offset# - 25))
Button(Class: btn btn-primary, Body: Previous, Page: AppPage, PageParams:"table_view_offset=#offset_previous#")
}
If(#record_count# >= Calculate(#table_view_offset# + 25)) {
SetVar(offset_next, Calculate(#table_view_offset# + 25))
Button(Class: btn btn-primary, Body: Next, Page: AppPage, PageParams:"table_view_offset=#offset_next#")
}
}
}
Div(Class: panel panel-primary) {
Form() {
Input(Name: message_input, Class: form-control, Type: text, Placeholder: "Write a message...", )
Button(Class: btn btn-primary, Body: Send, Contract: AppContract, Params: "Message=Val(message_input)", Page:AppPage, PageParams:"table_view_offset=#table_view_offset#")
}
}
Conclusions
Instead of expounding other important topics for application developers, such as layout styles, access permissions management and interaction between applications and resources, this tutorial introduces how to create a basic application for an ecosystem. For more information on these advanced topics, see other relevant documents.