Section [examples]

To get a reference to a section with the id mysection contained within the page mypage.

Oitem = Lianja.getElementByID("mypage.mysection")

https://www.lianja.com/doc/index.php/Working_with_the_Lianja_Object_Model


// to set the value of an Attribute

Lianja.get("pageid.sectionid").setAttribute("title","Section1")

Note: on the desktop, the shortened form setAttr(name,value) is also available.

// to get the value of an Attribute

cTitle = Lianja.get("pageid.sectionid").getAttribute("title")

Note: on the desktop, the shortened form getAttr(name) is also available.

https://www.lianja.com/doc/index.php/Attachments_Section_Attributes


// Collapsed delegate

Lianja.get("pageid.sectionid").collapse()
Lianja.showDocument("page:pageid.sectionid?action=collapse")
Lianja.showDocument("section:sectionid?action=collapse")
// Expanded delegate

Lianja.get("pageid.sectionid").expand()
Lianja.showDocument("page:pageid.sectionid?action=expand")
Lianja.showDocument("section:sectionid?action=expand")

https://www.lianja.com/doc/index.php/Custom_Delegates


There are three property selectors to provide CSS skinning of the Footer buttons:

  • lianja_ui_custom_button
  • lianja_ui_custom_button_hover
  • lianja_ui_custom_button_pressed

e.g.

[lianja_ui_custom_button="1"] { border:1px solid white; background black; color: white; font: bold 16px; }
[lianja_ui_custom_button_hover="1"] { background: #cfcfcf; }
[lianja_ui_custom_button_pressed="1"] { background: lightblue; }

 

Lianja/VFP function example

////////////////////////////////////////////////////////////////
// Event delegate for 'custommenu' event
proc employees_section1_custommenu(selitem)
	do case
	case selitem = "page2"
		messagebox("You selected page2")
	case selitem = "page3"
		messagebox("You selected page3")
	otherwise
		messagebox("You selected page4")
	endcase
endproc

JavaScript function example

////////////////////////////////////////////////////////////////
// Event delegate for 'custommenu' event
function employees_section1_custommenu(selitem)
{
	if (selitem == "page2")
	{
		messagebox("You selected page2");
	}
	else if (selitem == "page3")
	{
		messagebox("You selected page3");
	}
	else
	{
		messagebox("You selected page4");
	}
};

https://www.lianja.com/doc/index.php/Section_Footers


Custom section menu

Lianja/VFP function example

////////////////////////////////////////////////////////////////
// Event delegate for 'customsectionmenu' event
proc employees_section1_customsectionmenu(selitem)
	do case
	case selitem = "page2"
		messagebox("You selected page2")
	case selitem = "page3"
		messagebox("You selected page3")
	otherwise
		messagebox("You selected page4")
	endcase
endproc

JavaScript function example

////////////////////////////////////////////////////////////////
// Event delegate for 'customsectionmenu' event
function employees_section1_customsectionmenu(selitem)
{
	if (selitem == "page2")
	{
		messagebox("You selected page2");
	}
	else if (selitem == "page3")
	{
		messagebox("You selected page3");
	}
	else
	{
		messagebox("You selected page4");
	}
};

https://www.lianja.com/doc/index.php/Section_Menus


Custom search panel

Lianja/VFP function example

////////////////////////////////////////////////////////////////
// handlers for the Search Panel
proc sp_search_handler()
	Lianja.showDocument("section:section1?action=search&text="+sp_textbox.text)
endproc
 
proc sp_reset_handler()
	Lianja.showDocument("section:section1?action=search&text=")
	sp_textbox.text = ""
endproc
 
 
////////////////////////////////////////////////////////////////
// Event delegate for 'searchpanel' event
proc Customers_section1_searchpanel()
	sp_container = createObject("container")
	sp_container.addObject("sp_label", "label")
	sp_label.move(5, 3, 80, 20)
	sp_label.text = "Company Name"
	sp_container.addObject("osp_textbox", "textbox")
	sp_textbox = osp_textbox
	osp_textbox.move(85, 3, 100, 20)
	sp_container.addObject("sp_search", "commandbutton")
	sp_search.move(190, 3, 60, 20)
	sp_search.text = "Search"
	sp_search.click = sp_search_handler
	sp_container.addObject("sp_clear", "commandbutton")
	sp_clear.move(255, 3, 60, 20)
	sp_clear.text = "Reset"
	sp_clear.click = sp_reset_handler 
	this.addSearchPanel(sp_container)
endproc

JavaScript function example

////////////////////////////////////////////////////////////////
// Event delegate for 'searchpanel' event
function page1_section1_searchpanel()
{
	sp_container = createObject("container");
	sp_container.addObject("sp_label", "label");
	sp_label.move(5, 3, 100, 20);
	sp_label.text = "Company Name";
	sp_container.addObject("osp_textbox", "textbox");
	sp_textbox = osp_textbox;
	osp_textbox.move(105, 3, 280, 20);
	sp_container.addObject("sp_search", "commandbutton");
	sp_search.move(400, 3, 60, 20);
	sp_search.text = "Search";
	sp_search.click = sp_search_handler;
	sp_container.addObject("sp_clear", "commandbutton");
	sp_clear.move(465, 3, 60, 20);
	sp_clear.text = "Reset";
	sp_clear.click = sp_reset_handler ;
	Lianja.get("page1.section1").addSearchPanel(sp_container);
};
 
////////////////////////////////////////////////////////////////
// handlers for the Search Panel
function sp_search_handler()
{
	Lianja.showDocument("section:section1?action=search&text="+sp_textbox.text);
};
 
function sp_reset_handler()
{
	Lianja.showDocument("section:section1?action=search&text=");
	sp_textbox.text = "";
};

https://www.lianja.com/doc/index.php/Section_Search_Panels


Caption attribute can be queried or changed programmatically using Lianja.getElementByID(“<item>”).caption.

cVar = Lianja.getElementByID("page1.section1").caption

custom BROWSE or EDIT command to be executed in this section.

BROWSE NOEDIT FIELDS name,account,amount=items*itemcount:h"Total

Name attribute can be queried or changed programmatically using Lianja.getElementByID(“<item>”).id.

cVar = Lianja.getElementByID("page1").id
cVar = Lianja.getElementByID("page1.section1").id
cVar = Lianja.getElementByID("page1.section1.field1").id

Type attribute can be queried programmatically using Lianja.getElementByID(“<item>”).type.

cVar = Lianja.getElementByID("page1.section1").type
cVar = Lianja.getElementByID("page1.section1.field1").type

https://www.lianja.com/doc/index.php/Details_Attributes


 

Custom sections [examples]

Custom Sections are built using the Lianja UI Framework. When building a Custom Section you should subclass the Section class.

E.g. Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_vfp4

//
// Lianja custom section for page "page1" section "section1"
//
//------------------------------------------------------------------------------
// declare a namespace - this is added by default when you use the template code
namespace custom_vfp
 
//------------------------------------------------------------------------------
// when a namespace is active public variables are added to the namespace
public ui_grid
 
//------------------------------------------------------------------------------
// Step 1: Define the classes we need
// Note that all Lianja UI Framework classes can be subclassed in Visual FoxPro
//
// Subclass a Section 
// Note how the event procedures are defined. These correspond to the navigation
// buttons in the section header.
define class page1_section1 as section
	proc init()
		// place your section "init" code here
	endproc
	proc add()
		// place your section "add" code here
	endproc
	proc delete()
		// place your "delete" code here
	endproc
	proc first()
		// place your "first" code here
	endproc
	proc previous()
		// place your move "previous" code here
	endproc
	proc next()
		// place your move "next" code here
	endproc
	proc last()
		// place your "last" code here
	endproc
	proc watch()
		// place your "watch" code here
	endproc
	proc refresh()
		// place your "refresh" code here
	endproc
	proc edit()
		// place your "edit" code here
	endproc
	proc search()
		// place your "search" code here
	endproc
	proc save()
		// place your "save" code here
	endproc
	proc cancel()
		// place your "cancel" code here
	endproc
enddefine
//--------------------------------------------------------------------------
// Subclass a Listbox so that we can define the Click event procedure
define class cls_listbox as ListBox
	proc click()
		ui_grid.clear
		// Note how the AddItems method of Grid, ListBox and Combobox can take 
		// a SQL SELECT statement as an argument
		if trim(this.text) = "All"
			ui_grid.additems('select * from example where last_name != " "') 
		else
			ui_grid.additems('select * from example where;
			upper(left(last_name,1)) = "' + trim(this.text) + '"') 
		endif
		ui_grid.refresh()
	endproc
enddefine
//-------------------------------------------------------------------------------
// Define the main procedure in the section file that will create the section and
// return it to Lianja.
// Note that this must be the same name as the file in which it is contained in.
proc page1_section1 
 
//--------------------------------------------------------------------------
// Make sure the database is open
if database() != "southwind"
	open database southwind
endif
//--------------------------------------------------------------------------
// Step 2: Create the Custom Section object
page1_section1 = createobject("page1_section1")
//--------------------------------------------------------------------------
// Step 3: Create a PageFrame class and add it to the Section
page1_section1.addobject("tabs", "pageframe")
//--------------------------------------------------------------------------
// Step 4: Add a Page to the PageFrame class and set some of its properties
tabs.addobject("ui_tab_customers", "page")
ui_tab_customers.caption = "Customers"
ui_tab_customers.show
//--------------------------------------------------------------------------
// Step 5: Add a Container to the Page and set some of its properties
ui_tab_customers.addobject("ui_cont", "container")
ui_cont.autosize = .t.
ui_cont.backcolor = "lightblue"
ui_cont.layout = "horizontal"
ui_cont.margin = 5 
ui_cont.spacing = 5
ui_cont.show
//--------------------------------------------------------------------------
// Step 6: Add a subclassed ListBox to the Container and set some of its properties
ui_cont.addobject("ui_listbox", "cls_listbox")
ui_listbox.fixedwidth = 200
//--------------------------------------------------------------------------
// Step 7: Invoke the AddItems method with a comma-separated list of items
// to add to the ListBox
ui_listbox.additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z")
ui_listbox.show
//--------------------------------------------------------------------------
// Step 8: Add a Grid to the Container 
// Note that ui_grid is a namespace variable
ui_cont.addobject("ui_grid", "grid")
ui_grid.show
ui_grid.rowheight = 20 
ui_grid.readonly = .t.
ui_grid.recordmark = .f.
ui_grid.closable = .f.
ui_grid.caption = "Sample data"
ui_grid.additems('select * from example where last_name != " "') 
ui_grid.refresh
ui_grid.autofit
//--------------------------------------------------------------------------
// Step 9: Add a couple more Page classes to the PageFrame
tabs.addobject("ui_tab_orders", "page")
ui_tab_orders.caption = "Orders"
tabs.addobject("ui_tab_shippers", "page")
ui_tab_shippers.caption = "Shippers"
//--------------------------------------------------------------------------
// Step 10: now we must return the Section back to Lianja
return page1_section1

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Visual_FoxPro


Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container.  e.g.

// create a new object variable called "mygrid" which is a "Grid" 
myobj.addobject("mygrid", "grid")

Container classes are UI classes that can have other UI classes added to them and include the following.

  • Commandgroup
  • Container
  • Control
  • Gadget
  • Grid
  • Page
  • Pageframe
  • Section
  • Splitter
  • Tree

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Visual_FoxPro


All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class. e.g.

Some common properties:

  • Left
  • Top
  • Width
  • Height
  • BackColor
  • ForeColor

Some common methods:

  • show
  • hide

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

define class mybutton as commandbutton
 proc click( )
   MessageBox("You clicked the button!")
 endproc
enddefine

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Visual_FoxPro


PHP:

All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class.

Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_php4

//--------------------------------------------------------------------------
//
// Lianja custom PHP section
//
//--------------------------------------------------------------------------
// Important note. In PHP to access outer variables from within class 
// methods you must declare them global and then specify global again
// within the class method
global $ui_grid;
global $ui_listbox;
// You can write to the console log from PHP like this 
Lianja::writeLog("Hello from PHP");
//--------------------------------------------------------------------------
// Step 1: Define the classes we need
// Note how the Lianja UI Framework classes are subclassed in PHP 
// using the __construct() magic method.
class mySection extends Lianja     
{
    function __construct()
    {
        parent::__construct("Section");
    }
 
    function add()
    {
        Lianja::showMessage("add() was called");
    }
 
    function delete()
    {
        Lianja::showMessage("delete() was called again");
    }
 
    function first()
    {
        Lianja::showMessage("first() was called");
    }
 
    function previous()
    {
        Lianja::showMessage("previous() was called");
    }
 
    function next()
    {
        Lianja::showMessage("next() was called");
    }
 
    function last()
    {
        Lianja::showMessage("last() was called");
    }
 
    function watch()
    {
        Lianja::showMessage("watch() was called");
    }
 
    function edit()
    {
        Lianja::showMessage("edit() was called");
    }
 
    function save()
    {
        Lianja::showMessage("save() was called");
    }
 
    function cancel()
    {
        Lianja::showMessage("cancel() was called");
    }
 
    function refresh()
    {
    	;
    }
}
//--------------------------------------------------------------------------
// Note how the click() event handler for the Listbox is defined in PHP 
// just as a normal class method.
class myListbox extends Lianja
{
    function __construct()
    {
        parent::__construct("Listbox");
    }
 
    function click()
    {
        // Important note. In PHP to access outer variables from within class 
        // methods you must declare them global and then specify global again
        // within the class method
        global $ui_grid;
        global $ui_listbox;
        $ui_grid->clear();  
        // Note how the AddItems" method of Grid, ListBox and ComboBox can take 
        // a SQL SELECT statement as an argument
        if ($ui_listbox->text == "All")
        {
            $ui_grid->additems('select * from southwind!example where 
                last_name != " "');
        }
        else
        { 
            $ui_grid->additems('select * from southwind!example where
                upper(left(last_name,1)) = "' . $ui_listbox->text . '"');
        }
        $ui_grid->refresh();
        Lianja::writeLog("clicked again");
    }
}
//--------------------------------------------------------------------------
// Step 2: Create the Section object
$page1_section1_section = Lianja::createObject("Section"); 
//--------------------------------------------------------------------------
// Step 3: Create a PageFrame object and add it to the Section
$page1_section1_section->addObject("ui_tabs", "Pageframe");
 
//--------------------------------------------------------------------------
// Step 4: Add a Page to the PageFrame object and set some of its properties
$ui_tabs->addobject("ui_tab_customers", "Page");
$ui_tab_customers->caption = "Customers";
 
//--------------------------------------------------------------------------
// Step 5: Add a Container to the Page and set some of its properties
// The AddObject() method takes the objectname as the first arg then 
// the classname as the second.
$ui_tab_customers->addobject("ui_cont", "Container"); 	
$ui_cont->autosize = 1;
$ui_cont->backcolor = "lightgray";
$ui_cont->layout = "horizontal";
$ui_cont->margin = 5;
$ui_cont->spacing = 5;
 
//--------------------------------------------------------------------------
// Step 6: Add a ListBox to the Container and set some of its properties
$ui_cont->addobject("ui_listbox", "myListbox");
$ui_listbox->fixedwidth = 200; 
//--------------------------------------------------------------------------
// Step 7: Invoke the AddItems method with a comma-separated list of items 
// to add to the ListBox
$ui_listbox->additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
 
//--------------------------------------------------------------------------
// Step 8: Add a Grid to the Container
$ui_cont->addobject("ui_grid", "Grid");
$ui_grid->rowheight = 20;
$ui_grid->readonly = 1;
$ui_grid->recordmark = 0;
$ui_grid->closable = 0;
$ui_grid->caption = "Sample data";
$ui_grid->additems('select * from southwind!example where last_name != " "');
$ui_grid->autofit( );
$ui_grid->show();
//--------------------------------------------------------------------------
// Step 9: Add a couple more Page objects to the PageFrame
$ui_tabs->addobject("ui_tab_orders", "Page");
$ui_tab_orders->caption = "Orders";
$ui_tabs->addobject("ui_tab_shippers", "Page");
$ui_tab_shippers->caption = "Shippers";
//--------------------------------------------------------------------------
// Step 10: Return the section back to the Lianja. We accomplish this by assigning
// it to the global returnvalue variable.
$returnvalue = $page1_section1_section;

When you develop a Custom Section or Gadget in PHP, the Lianja UI Framework makes available several built-in global PHP functions to enable you to interact with Lianja and the embedded Lianja database. This provides you with a embedded PHP database with full SQL and noSQL data access.

  • Lianja::createObject(objectname, classname)
  • Lianja::openDatabase(dbname)
  • Lianja::showMessage(messagetext)
  • Lianja::execute(lianjacommandstring)
  • Lianja::evaluate(lianjaexpression)

Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container. The first argument is the name of the object you want to create and the second is the name of the class that you want to instantiate e.g.

// create a new object called "myobj" which is a "Container"
$myobj = Lianja::createObject("Container");
 
// add a new object variable called "mygrid" which is a "Grid" 
$myobj->addObject("mygrid", "Grid");

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

class myButton extends Lianja
{
    function __construct()
    {
        parent::__construct("CommandButton");
    }
    
    function click()
    {
        Lianja::showmessage("You clicked the button!");
    }
}

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_PHP


Python:

Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_py4

#
# Lianja custom Python section "page1_section1"
#
import Lianja
#--------------------------------------------------------------------------
# Step 1: Define the classes we need
# Note that all Lianja UI Framework classes can be subclassed in Python
class mySection(Lianja.Section):
    def add(self):
        Lianja.showMessage("add() was called")
 
    def delete(self):
        Lianja.showMessage("delete() was called")
 
    def first(self):
        Lianja.showMessage("first() was called")
 
    def previous(self):
        Lianja.showMessage("previous() was called")
 
    def next(self):
        Lianja.showMessage("next() was called")
 
    def last(self):
        Lianja.showMessage("last() was called")
 
    def refresh(self):
        pass
 
    def search(self):
        pass
 
    def watch(self):
        Lianja.showMessage("watch() was called")
 
    def edit(self):
        Lianja.showMessage("edit() was called")
 
    def save(self):
        Lianja.showMessage("save() was called")
 
    def cancel(self):
        Lianja.showMessage("cancel() was called")
 
#--------------------------------------------------------------------------
# Note how the click() event handler for the ListBox is defined in Python
class myListbox(Lianja.Listbox):
    def click(self):
        ui_grid.clear( )
        # Note how the AddItems method of Grid, ListBox and ComboBox can take 
        # a SQL SELECT statement as an argument
        if ui_listbox.text == "All":
            ui_grid.additems('select * from southwind!example where last_name != " "')
        else: 
            ui_grid.additems('select * from southwind!example where upper(left(last_name,1)) \
            = "' + ui_listbox.text + '"')
        ui_grid.refresh( )
 
#--------------------------------------------------------------------------
# Step 2: Create the Section object
# Note that the CreateObject() method needs two args: objectname, classname
oSection = Lianja.createObject("oSection", "mySection")
oSection.backcolor = "lightgreen"
oSection.caption = "This is a custom Python section"
 
#--------------------------------------------------------------------------
# Step 3: create a PageFrame object and add it to the Section
oSection.addObject("ui_tabs", "Pageframe")
 
#--------------------------------------------------------------------------
# Step 4: Add a Page to the Pageframe object and set some of its properties
ui_tabs.addobject("ui_tab_customers", "Page")
ui_tab_customers.caption = "Customers"
 
#--------------------------------------------------------------------------
# Step 5: Add a Container to the Page and set some of its properties
# The AddObject() method takes the objectname as the first arg then the classname as the second.
ui_tab_customers.addobject("ui_cont", "Container") 	
ui_cont.autosize = 1
ui_cont.backcolor = "lightblue"
ui_cont.layout = "horizontal"
ui_cont.margin = 5
ui_cont.spacing = 5
 
#--------------------------------------------------------------------------
# Step 6: Add a ListBox to the Container and set some of its properties
ui_cont.addobject("ui_listbox", "myListbox")
ui_listbox.fixedwidth = 200
 
#--------------------------------------------------------------------------
# Step 7: Invoke the AddItems method with a comma separated list of items to add to the ListBox
ui_listbox.additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z")
 
#--------------------------------------------------------------------------
# Step 8: Add a Grid to the Container
ui_cont.addobject("ui_grid", "Grid")
ui_grid.rowheight = 20
ui_grid.readonly = 1
ui_grid.recordmark = 0
ui_grid.closable = 0
ui_grid.caption = "Sample data"
ui_grid.additems('select * from southwind!example where last_name != " "')
ui_grid.autofit( )
ui_grid.refresh( )
 
#--------------------------------------------------------------------------
# Step 9: Add a couple more Page objects to the PageFrame
ui_tabs.addobject("ui_tab_orders", "Page")
ui_tab_orders.caption = "Orders"
ui_tabs.addobject("ui_tab_shippers", "Page")
ui_tab_shippers.caption = "Shippers"
 
#--------------------------------------------------------------------------
# Step 10: Return the section back to the Lianja. We accomplish this by assigning
# it to the global returnvalue variable.
returnvalue = oSection

When you develop a Custom Section or Gadget in Python, the Lianja UI Framework makes available several built-in global Python functions to enable you to interact with Lianja and the embedded Lianja database. This provides you with a embedded Python database with full SQL and noSQL data access.

# include the lianja module
import Lianja
  • Lianja.createObject(objectname, classname)
  • Lianja.openDatabase(dbname)
  • Lianja.showMessage(messagetext)
  • Lianja.execute(lianjacommandstring)
  • Lianja.evaluate(lianjaexpression)

Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container. The first argument is the name of the object you want to create and the second is the name of the class that you want to instantiate e.g.

# include the lianja module
import Lianja
 
# create a new object called "myobj" which is a "Container"
myobj = Lianja.createObject("myobj", "Container")
 
# add a new object variable called "mygrid" which is a "Grid" 
myobj.addObject("mygrid", "Grid")

Container classes are UI classes that can have other UI classes added to them and include the following.

  • Commandgroup
  • Container
  • Control
  • Gadget
  • Grid
  • Page
  • Pageframe
  • Section
  • Splitter
  • Tree

All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class. e.g.

Some common properties:

  • Left
  • Top
  • Width
  • Height
  • BackColor
  • ForeColor

Some common methods:

  • show
  • hide

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

import Lianja
 
class mybutton(Lianja.Commandbutton):
    def click(self):
        Lianja.showMessage("You clicked the button!")

ty classes available in the Lianja UI Framework

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Python


JS:

Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_js4

//
// Lianja custom JavaScript section "page1_section1"
//
//--------------------------------------------------------------------------
// Step 1: Create the custom section object
// Note that the CreateObject() function needs two args: objectname, classname
oSection = createobject("oSection", "section");
 
//--------------------------------------------------------------------------
// Step 2: Create a PageFrame class and add it to the Section
oSection.addobject("ui_tabs", "pageframe");
 
//--------------------------------------------------------------------------
// Step 3: Add a Page to the PageFrame class and set some of its properties
ui_tabs.addobject("ui_tab_customers", "page");
ui_tab_customers.caption = "Customers";
 
//--------------------------------------------------------------------------
// Step 4: Add a Container to the Page and set some of its properties
// the AddObject() method takes the object name as the first arg then the 
// class name as the second.
ui_tab_customers.addobject("ui_cont", "container") ;	
ui_cont.autosize = 1;
ui_cont.backcolor = "lightblue";
ui_cont.layout = "horizontal";
ui_cont.margin = 5;
ui_cont.spacing = 5;
 
//--------------------------------------------------------------------------
// Step 5: Add a ListBox to the Container and set some of its properties
ui_cont.addobject("ui_listbox", "Listbox");
ui_listbox.fixedwidth = 200;
 
//--------------------------------------------------------------------------
// Step 6: Declare event callbacks for objects using JavaScript closures
// like this:
ui_listbox.click = function( )
{
    ui_grid.clear( );
    // Note how the AddItems method of Grid, LisBbox and ComboBox can take 
    // a SQL SELECT statement as an argument
    if (ui_listbox.text.trim( ) == "All")
    {
        ui_grid.additems('select * from southwind!example where last_name != " "'); 
    } 
    else 
    {
        ui_grid.additems('select * from southwind!example where ' +
                    'upper(left(last_name,1)) = "' + ui_listbox.text.trim( ) + '"');
    }
    ui_grid.refresh( );
};
 
//--------------------------------------------------------------------------
// Step 7: Invoke the AddItems method with a comma-separated list of items
// to add to the Listbox
ui_listbox.additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
 
//--------------------------------------------------------------------------
// Step 8: Add a Grid to the Container
ui_cont.addobject("ui_grid", "grid");
ui_grid.show( );
ui_grid.rowheight = 20;
ui_grid.readonly = 1;
ui_grid.recordmark = 0;
ui_grid.closable = 0;
ui_grid.caption = "Sample data";
ui_grid.additems('select * from southwind!example where last_name != " "');
ui_grid.autofit( );
ui_grid.refresh( );
 
//--------------------------------------------------------------------------
// Step 9: Add a few more Page classes to the PageFrame
ui_tabs.addobject("ui_tab_orders", "page");
ui_tab_orders.caption = "Orders";
ui_tabs.addobject("ui_tab_shippers", "page");
ui_tab_shippers.caption = "Shippers";
 
//--------------------------------------------------------------------------
// Step 10: Now return the section back to the Lianja. We accomplish
// this by assigning it to the returnvalue variable.
returnvalue = oSection;

When you develop a Custom Section or Gadget in JavaScript, the Lianja UI Framework makes available several built-in global JavaScript functions to enable you to interact with Lianja and the embedded Lianja database. This provides you with a embedded JavaScript database with full SQL and noSQL data access.

  • createObject(objectname, classname)
  • openDatabase(dbname)
  • showMessage(messagetext)
  • execute(lianjacommandstring)
  • evaluate(lianjaexpression)
  • require(filename)
  • require_once(filename)
  • include(filename)
  • include_once(filename)

Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container. The first argument is the name of the object you want to create and the second is the name of the class that you want to instantiate e.g.

// create a new object called "myobj" which is a "Container"
myobj = createObject("myobj", "Container");
 
// add a new object variable called "mygrid" which is a "Grid" 
myobj.addObject("mygrid", "grid");

Container classes are UI classes that can have other UI classes added to them and include the following.

  • Commandgroup
  • Container
  • Control
  • Gadget
  • Grid
  • Page
  • Pageframe
  • Section
  • Splitter
  • Tree

All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class. e.g.

Some common properties:

  • Left
  • Top
  • Width
  • Height
  • BackColor
  • ForeColor

Some common methods:

  • show
  • hide

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

myobj = createobject("myobj", "Commandbutton");
 
// You declare event callbacks for objects using javascript closures like this:
myobj.click = function( )
{
    // place your event handler here
};

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_JavaScript


 

Section

Q:

I have a page with only one canvas section. The section height is 755.
In webapp view/ and browser preview, i gets truncated and there is no vertical scroll bar.

Name: lf-longpage.png Views: 37 Size: 22.5 KB

A:

The Page scrollbar is only available in the desktop client. If you split the controls between 2 canvas sections you can expand/collapse the sections as required or use ‘accordion behavior‘ to handle it automatically.

https://www.lianja.com/doc/index.php/Accordion_Behavior


You need to decide will you use Standard sections, Custom sections or Canvas sections.

Canvas is free style. There you can play with containers and stack stuff horizontally as you wish. con: No responsive.
Custom is by code. Define class, define class…
Standard has integrated CRUD and less freedom but less work.

In web pages you see 3 column design mostly.
Lianja has left sidebar, right sidebar, and the center is occupied by section.


Q:

I have a CommandButton on a Canvas section. There are no other sections on the page. The page has Stretch Last Section = True.

I want the CommandButton to be anchored to the bottom right corner and I want it’s size to remain constant.

I have set Anchor=12 (which is what I would have used in VFP). This results in it being anchored to the bottom right corner, but the size changes based on the size of the page.

A:

You can layout your controls in the resize delegate.
Look at the code in the example_canvaslayoutjs app.
The resize delegate is in javascript but the logic is the same in VFP.


if you open a file explorer window you can drag an image file onto a section to make it the background for the section. The image will automatically be copied into your App directory and set as the background image.


Q:

How do I stack sections horizontally? Say I have a grid on the left side and I want a form on the right side.

A:

You can layout a form section horizontally using a grid gadget and/or adding dividers.


Q:

How do I change the background colour of the section?

A:

look in lib:/pagecenter/pagecenter.rsp at line 16. You can customize the background.

Section

Use the section.requery() method OR set the section.sql property – not both, e.g.

// section.requery()
// Specify everything after the WHERE (apologies if I misled you on this syntax previously)

Code:
Lianja.get("page1.section2").requery([userid='{Lianja.get("page1.section1.field1").text}'] )

OR
// section.sql
// Specify the full SQL statement

Code:
Lianja.get("page1.section2").sql = [select * from <basetable> where userid='{Lianja.get("page1.section1.field1").text}']

If your current App is failing to load, use the Versions workspace to restore an earlier version of your prg or open the prg in an external editor and comment out the lines (//) of your section.ready() event delegate.


Q:
How to add objects to a custom section
A:

Code:
define class page1_section1 as section
enddefine
define class contTopStatusBar as container
        layout = "vertical"
        fixedheight = 40
        backcolor = "white"
        add object buttonTest as commandbutton

enddefine

proc page1_section1 
        page1_section1 = createobject("page1_section1")
        page1_section1.addobject("cont1", "contTopStatusBar")
        cont1.buttontest.caption = "Hello"
        page1_section1.addobject("cont2", "contTopStatusBar")
        cont2.buttontest.caption = "World"
return page1_section1

define class herbButton as commandbutton
proc click()
Lianja.showMessage("Button was clicked")
endproc 

enddefine

define class contTopStatusBar as container
layout = "vertical"
fixedheight = 40
backcolor = "white"
add object buttontest as herbButton

enddefine

proc page1_section1 
page1_section1 = createobject("page1_section1")

page1_section1.addobject("cont1", "contTopStatusBar")
cont1.buttontest.caption = "Hello"
page1_section1.addobject("cont2", "contTopStatusBar")
cont2.buttontest.caption = "World"

return page1_section1

Q:
The finished app has a section on the left hand side with such things as favourites, recently viewed which you can hide by clicking on the word hide. Is there any way of removing that whole section ? Also is it possible to remove the navigation buttons from the bottom of the page which relate to the customer records at the top ?
A:
Yes – that’s called the Left Sidebar. Look in the Page Attributes (cog icon or double-click on header) and in the Left Sidebar sub-section uncheck ‘Show left sidebar‘.
In the Page Attributes ‘Appearance’ sub-section you will find ‘Hide actionbar‘ – check that to remove the navigation buttons.


Q:
How do use hwnd to get the id for a section, or a gadget?
A:
In LianjaDemo, from the console:

Code:
lo = lianja.get("customers")
? lo.hwnd

Better to create a custom section, add a container that auto sizes into the section and use its hwnd. Why? Because it excludes the area occupied by the header, header menu and footer menu.


Q:
1. Adding the canvas and grid sections to my page works just fine but I cannot add a button to the canvas, the commented -out code just doesn’t work – am I doing something wrong?
2. Running this code as-is in the app builder (ie. forget the button part), I see the new sections but if I try to add any gadgets manually to the canvas (from the ‘Advanced’ menu option at the bottom of the app builder) then the IDE crashes (with the “lianja.exe has stopped working” message).

Code:
proc page1_section2_field2_click()

        //Get a reference to the page
        page = Lianja.getElementByID("page1")

        //Add a canvas section to the page
        page.AddSection("custCanvas", "canvas")
        canvasSection = Lianja.getElementByID("page1.custCanvas")
        canvasSection.caption = "New Canvas"

        //Add a button to the canvas
        /*NOT WORKING
        canvasSection.AddObject("myButton", "commandbutton")
        btn = Lianja.getElementByID("page1.custCanvas.myButton")
        btn.move(20,20,100,50)
        */
       
        //Add a grid section to the page
        page.AddSection("custGrid", "grid")
        gridSection = Lianja.getElementByID("page1.custGrid")
        gridSection.caption = "New Grid"

endproc

A:
You cannot create canvas sections dynamically using addobject().
Canvas sections are designed visually.
Custom sections are created dynamically


‘Enhanced “Form” section layout to provide a more compelling UI for Web/Mobile Apps using NoCode.’ — my understanding of this, in plain language, is that just about everything you want to design in an app will be doable in a Form section, and will be responsive.
With the new UI in 2.1, and the metadata enhancements, this takes app development to a new level. This is huge, as this is the first step toward using all the other stuff above.


Q:
On a canvas section I’m trying to insert some custom buttons mainly for navigation and basic actions. I’ve tried several ways but with no luck.
On exemple, for a “move to next record” button in a desktop app what I’m doing is to create a new page(page1), a new canvas section (section1), drop in some record fields, and then I insert a command button, typing in the Default action field of the control:

Code:
section:section1?action=next

.
When I click it, it seems that nothing happens, or almost the fields are not refreshing. How can I use the “default actions” in a button in the canvas section?
A:
If you put the code in the Click event delegate for your button that will work.

JavaScript:

Code:
////////////////////////////////////////////////////////////////
// Event delegate for 'click' event
function page1_section1_field1_click()
{
        showdocument("section:section1?action=next");
};

VFP (remember to use JavaScript if you want to run in the Lianja Web Client)

Code:
////////////////////////////////////////////////////////////////
// Event delegate for 'click' event
proc page1_section1_field1_click()
        showdocument("section:section1?action=next")endproc

A2:
It seems like you added a canvas section and then added some textfields, and some buttons.
I am using the southwind database in my example.

1. Drag the fields from the table you want onto the canvas from table itself. I have selected the ‘example’ table

2. Add your buttons.
3. In the button that you want to use to move the records forward, add the following code. On my section, I named them txtNext and txtPrior (not case sensitive in VFP).

Here is the code from click events.

Code:
// Event delegate for 'click' event
proc page1_section1_txtPrior_click()
select example
if not bof()
skip -1
Lianja.get("page1.section1").refresh
else
wait window " You are on the first record"
endif
endproc

////////////////////////////////////////////////////////////////
// Event delegate for 'click' event
proc page1_section1_txtNext_click()
select example
if not eof()
skip 1
Lianja.get("page1.section1").refresh
else
wait window " You are on the last record"
endif
endproc

Q:
when one would use the standard sections and when or why the custom?
A:
That’s a tough one to answer, because I think it’s based on personal preferences. Although there are some things like custom grid section menus, that have to be done via custom code (meaning create container -> add objects etc..).

The other differences to me boils down to 2 things.
1. Re-using custom classes.
2. Layout management

In a custom sections, you can re-use classes that you have saved in the library. I Know that version 3.1 will have a visual Component builder, but that is still in the pipeline.

Custom sections can resize themselves based on how you specify the layout.
Canvas sections are not naturally responsive -but you can resize them via code. That can be tough if you have many objects.

I don’t know which one I use more though, I think it also depends on what I am doing.
You really cant go wrong with either one.


This is a quick intro to using custom VFP sections in Lianja.
https://youtu.be/22KwE857M24


Hide a section at runtime


Here is an explanation of dilema standard-custom-canvas:

As you know there are a lot of pre-built sections and I always recommend that you look into using these standard sections as your first choice rather than coding.

The question you really have to answer first is “Where do I want these Apps I build to run“?

If you are targeting desktop only then I would say go ahead and use whatever you feel comfortable with.

If you build your apps out of the standard sections then it will pretty much run straight off in the cloud too.
These built-in sections have been chosen due to the fact that they are common high level building blocks that you can visually build your Apps out of.
Its a sort of lego for cross-UI database apps.
The standard sections that I would recommend you using the most (if at all possible) are; Form, Grid, Report, Chart, WebView, Calendar, Attachment, ImageStrip, and TabView.

There are obvious tradeoffs that you have to make if you want your apps to be desktop, web and mobile — and after all, thats what Lianja is all about — apart from the cross platform nature of it; Windows, Mac and Linux.

“Custom sections” are code centric.
They can be developed in the Visual FoxPro compatible scripting, PHP, Python or JavaScript — whatever you are comfortable with in fact.

Canvas sections do not have the same level of functionality as you have in the page builder when you are visually designing pages out of forms, grids and webviews.
You have to basically “paint” them yourself — hence the name “Canvas”.

It is important to understand that just because it is not immediately apparent how to do something in standard sections not to assume that the standard sections can’t do it.
I don’t see building apps using standard sections without coding as being for beginners.
The idea is that domain knowledge developers should be able to build an App with minimal coding.

You can move fields around in form sections and separate them into columns using dividers.

To build a composite form you would use two sections one above the other and “Hide the section headers”.

You can change values in other fields as data is entered now.

You can build form sections into horizontal columns using the dividers i mention above to separate the form off into columns.

…you have “rules” that control “Visibility” and “Readonly” that are evaluated as data is displayed and entered in the form so the form can re-arrange itself.

…the section footer can contain hyperlinks that can be clicked and change the “State” in which the form is in. This can hide/show certain fields.

When working with Canvas, think Container: the Container moves controls around the same way as Form sections.

You can designate a Canvas section to be displayed only for desktop and web (big tablets); and have an alternate Form section that you designate only for Mobile (phones, small tablets). That’s controlled by section by the checkboxes at the bottom of the Section attributes.


Q:
how to hide/show a single element in a section?
I understand how to hide pages and sections. For some reason, I cannot find a reference to it hiding and showing a single element. I am trying to hide a textbox upon data change of another textbox.

Code:
proc Generate_line_detail_stkno_changed()
quantity.hide
getlineitemfrompricelist()
endproc

A:
Try this:

Code:
// Event delegate for 'changed' event
proc page1_section1_field1_changed()
    quantity=Lianja.get("quantity")
    quantity.hide
endproc

In App inspector you can see your quantity field is fully qualified as:

page: page1.section1.quantity

or in your case, I suppose:

page: Generate_line.detail.quantity

To apply “hide”, you need to reference this field object by Lianja.get(…), not by name only.

Shorten way:

Code:
// Event delegate for 'changed' event
proc page1_section1_field1_changed()
    Lianja.get("quantity").hide
endproc

Q:
I want a section initially hidden upon system start up. Where should I place this code?

Code:
showdocument("section:section1?action=hide")

I tried to place it in the ready delegate of the section itself and in the ready delegate of the page where the section is located but got the same behavior the section was not hidden upon the system start up.
Also, I tried to place the same code on the click delegate of the cancel button and the section was hidden upon clicking the cancel button.
A:
I put your code

Code:
showdocument("section:section1?action=hide")

in page’s ready delegate of lianja_mobiledemo, and deployed it.
After that, in App Center the Section1 is not showing at start. As expected.

In development views in Lianja App Builder it is showing.
These are only development (pre)views and they can not 100% replace real runtime environment.
If they could, then we would not need Page Center on development machine.



Section

Q:
two Form sections. The first had Columns added by dragging the entire table from the Tables list.
The second had them
added individually by dragging them from the Column Names list.
Why does the former get navigation controls added automatically and the second does not? How do I add them to the second?
A:
Just save and reload the App and it will pick up that the section is data-bound and show the navigation in the Section header.


(?A):
it is possible to change both the database and table for a section, even if it’s grayed out.
For a form/grid/webview etc. section named mysection, use the console and issue:

Code:
lianja.get("mysection").database = "mynewdatabase"

Next: save the app and refresh it. You will see the new database name has been saved. Similary for the table (or anything else).


Q:
I have a project and successfully deployed it on LAN. But on the client PC not all fields are seen on the canvas section due to the small monitor screen. So the solution I have in mind is to put a scroll bar on the canvas section. Is that possible to put a scroll bar on canvas section when the monitor is too small to view all the fields on canvas?
A:
A canvas section is non responsive as you have discovered. A canvas section cannot be scrollable.
The
page containing the canvas section can be scrollable so play about with that setting in the page attributes.



Section

Q:
Is it possible to have a collapsible section start off collapsed?
I have several sections on a page and a few of them would only be occasionally used. So, it would be nice to have the page start with them collapsed so the other sections can be more visible.
A:
In the “Ready” delegate for the page you can collapse the sections.

Code:
Lianja.get("customers.section2").collapse()

Added a new section attribute “Apply rules on parent data change“. This causes the UI presentation rules to be evaluated dynamically as you navigate data in the parent section.
You can therefore
hide/show other related sections based on the data that is being displayed in the parent section.
Note that when the UI presentation rules are applied the “Visible When” and “Readonly When” conditions are evaluated. This is only
effective in runtime mode.


Visible when” and “Readonly when” are evaluated when you

Code:
Lianja.get("page.section").applyRules()

This happens automatically if you have set the section attribute “Apply rules on change” in the “UI Presentation Rules”.
This will then cause the UI to hide and show elements dynamically depending on the data being currently viewed.


Q:
It is possible to display a grid within a canvas section?
I don’t want the grid in a separate section, I want it included with the section being used to potentially display basic or related information.
Here’s what I’m thinking:
– Add a label
– Add a combobox
– Display values in a grid based on the selected combobox value. Data would possibly come a a virtual table.
Using Southwind as an example (albeit not the best example):
label: Expenses
combobox values: Monthly Expenses (as label) and values (choices) could be individual months
grid: display the orders for the selected month
A:
A page can be arranged out of numerous sections that can have the section header hidden at runtime. So the page acts and appears as one section although it has been visually designed out of many.
Sections can be grouped together (there is an example demo App showing how to achieve this) so they expand and collapse as one section.

There are various examples of this. The Custom Canvas Demo example App uses a TreeGrid.


SQL with {…} macros is used to relate the sections.


In v1.2.2 there is a new section attribute “Where condition” that can be used to requery() Virtual Tables dynamically. This is a SQL SELECT WHERE condition for your target SQL database.
It can be set dynamically:

Code:
Lianja.get("page1.section1").where = "account > 1000 and empid = '0001'"

or

Code:
Lianja.showDocument("page: page1.section1?action=where&text=account gt 1000 and empid eq '0001'"

(notice how I have specified the where condition above in OData format).
So If you are working with large amounts of data create your VT as SELECT… WHERE 1=0
Then change the “where condition” dynamically in your App ready delegate.


Q:
So then it wouldn’t matter if it was a foxpro or JavaScript section since the requery is at the section level and not at the cursor adaptor or recordset level.
A:
Yes thats correct. It only works against VTs as internally it issues a requery() for the VT. The cursoradaptor for the VT knows what section it is bound too so when the requery() completes the section is automatically refreshed.
Also remember that the “where condition” operates just like requery() method on the Virtual Table so it can also contain ORDER BY … LIMIT etc.
So it replaces everything after the WHERE in the Virtual Table definition.
This makes paging of data and changing order much easier.


Q:
I am trying to create a new record whenever the section is loaded. I am trying to do this with the init/ready delegate with the following code:

Code:
Lianja.showDocument("page:gCreateTasks.section:section1?action=add");

A:
That syntax looks wrong, try it in the JavaScript console.

Code:
page: page1.section1?action=add