Wednesday, February 23, 2011

Displaying data with the hb grid widget

The last posts show you how to get data records from a backend, and how to display them on a grid object using a widget. now is time to see the hb_grid in more detail.
Like you know the hb_grid widget let you show data in a tabular way. you can create many instances of a grid using only an hb_grid widget, like is shown on this image:

Every instance is completely independent from the others instances of the widget.
You use the dataProvider property to indicate to a grid where are the data to be show.
The data showed on a grid are tied to the variable containing those data when you use the dataProvider property with an arrayCollection variable, and if the user modify some data item on a grid he (she) really modify the variable containing that data.
now look at the following image:



The property that allow edit the data showed on a grid is the editable property, you must note that the grid has a editable property and the dataGridColumn has an editable property too, but this last one, if not indicated, is set to true by default.
Now watch this image:


On the above image there are two grids (grid1 and grid2), created using the same hb_grid widget, the left most grid (grid1) has its editable property set to true and the right most grid (grid2) has its editable property set to false, however when we change any data item on the grid 1 automatically the data are refreshed on the grid 2, like you can see on the second row (the 'titulo' column).
If you want to add a new row (either with data or not) you must to add the data to the dataProvider variable not to the widget, lets say you add the data to the variable containing the data for the grid.
in the same way if you want to delete a data row from the hb_grid widget you only must delete it in the variable associated to the dataProvider property.
The widget always is refreshed automatically when you change a data, add rows, or delete rows from the variable associated with the widget.
The variable that you assign to the dataProvider is a variable of type array or arrayCollection, where every element into the array corresponds to a data row in the grid, and every one of this elements really is an object with attributes which will be the columns (fields) of the hb_grid.
do you remember the previous posts ? there you find a line in the serverResponse event that look so:

var registros=page.loadArrayCollection(result.Table.serverInfo);

that line takes the data returned from the midleware and convert them into an arrayCollection, which could be used with the hb_grid. when the data are converted into the arrayCollection every data row (data base row) returned from the midleware is converted into a element (object) of the arrayCollection, and each element (object) into the array will has so many attributes like data fields (data base columns) has the returned rows .
to clarify this look this code:

// using an arrayCollection will ensure that the data are automatically refreshed
// the variable registros could be used assigned later to the dataProvider of an hb_grid widget
var registros=new ArrayCollection();
registros.addItem({id:10,name:"alex araya",valor:true});
registros.addItem({id:12,name:"jaime araya",valor:false});

the above code creates an arrayCollection with two elements. Its equivalent using an array is:

var registros=new Array();
registros.push({id:10,name:"alex araya",valor:true});
registros.push({id:12,name:"jaime araya",valor:false});

here we are constructing our array in a harcoded way. The first line creates a empty array, on the second we push our first element (data record) into the array with three attributes (data fields). this attributes are id, name and valor (value). the third line creates another data record into the array with the same attributes and other values for every attribute. this array could be used later like a dataProvider for the hb_grid.

Other useful properties of the hb_grid are:
selectedItem: it is an object that represents the selected row of the hb_grid, is null if there is no one row selected.
selectedIndex: it is a number representing the subscript in the array of the selected item of the hb_grid.
alpha: is the alpha transparency value of the hb_grid . Valid values are 0 (fully transparent) to 1 (fully opaque). The default value is 1. objects with alpha set to 0 are invisible.
enabled: (true/false) indicates whether the component (hb_grid) can accept user interaction.
id: is a string corresponding to the ID of the hb_grid. it could be useful to identify the hb_grid that has triggered an event, like you'll see later.
showHeaders: (true/false) indicates whether the widget should show column headers.
visible: (true/false) if true the hb_grid is visible, if false is invisible.
selectedItem: Represents a reference to the selected item in the data provider, if there is no item selected it will be null.
selectedIndex: is the index in the data variable (dataProvider property) of the selected item. If there is no selected item it will be -1.

The events triggered for the hb_grid are the following:

item_change: executed when
selectedIndex or selectedItem property changes as a result of user interaction. The parameters passed to your event script for this event are:
me: is the hb_grid instance that triggered the event.
info: is an object that in the case of this event will have the following attributes:
info.row: is the row of the hb_grid's cell where the user is now.
info.col: is the col of the hb_grid's cell where the user is now.

item_click: executed when the user click on a cell of the grid. The parameters passed to your event script for this event are:
me: is the hb_grid instance that triggered the event.
info: is an object that in the case of this event will have the following attributes:
info.row: is the row of the hb_grid's cell where the user made click.
info.col: is the col of the hb_grid's cell where the user made click.

item_editBeginning: executed when the user begins the editing of a cell. The parameters passed to your event script for this event are:
me: is the hb_grid instance that triggered the event.
info: is an object that in the case of this event will have the following attributes:
info.row: is the row of the hb_grid's cell being edited.
info.col: is the col of the hb_grid's cell being edited.
dataField: is the name of the field or property in the data associated with the item's column.


item_editEnd: executed when the user ends the editing of a cell. The parameters passed to your event script for this event are:
me: is the hb_grid instance that triggered the event.
info: is an object that in the case of this event will have the following attributes:
info.row: is the row of the hb_grid's cell being edited.
info.col: is the col of the hb_grid's cell being edited.
dataField: is the name of the field or property in the data associated with the item's column.
This event is cancelable, meaning that if you event script returns false, the value entered by the user will be rejected. This is useful for custom data validation.





The above image show you two grids (grid1 and grid2). Every event triggered for the grid2 (the right most grid) is registered in a text component trough scripting, so we can watch the moment when a event is triggered for the hb_grid.

The hb_grid allows you using other controls for data input instead of the default text control, like you see on the next image where you can see a combo box:


At the present the controls that you can use for editing a cell are:
- ComboBox
- CheckBox
- Text Input
- Button
- NumericStepper



post not ended...

Monday, February 21, 2011

Accessing databases with Hummingbird and scripting part II

On this post you will see how to create the midleware layer for our database sample application. we will use asp.net+fluorineFX framework.
If you had never used fluorineFX, you can visit:
http://www.fluorinefx.com/

if you want to learn how to preparing an asp.net project in order to use the fluorineFX framework visit:
http://www.fluorinefx.com/docs/fluorine/index.html

is very simple using fluorineFX with asp.net, and like you will see on the official documentation, you must to add a reference on the asp.net project to the fluorineFX framework, and then you are ready to coding.
You must to create a new project called 'WebServPortalFlex'.
Once you have your project configured to use fluorineFX, you must to create a new class called 'servicios' like you see on the following picture:


write a function called ejecuta_query and a function called obtenerPaginasUsuario inside the class servicios, with the following code:



private DataSet ejecuta_query(String query)
{

// you must to change the conexion variable to use your own conexion string
String conexion="server=localhost;database=dbtest;uid=dbuserid;pwd=dbpassword;";

SqlConnection con=new SqlConnection(conexion);
DataSet ds=new DataSet();
SqlDataAdapter da = new SqlDataAdapter(query,con);
try
{
da.Fill(ds);
}
catch(Exception er)
{
con.Close();
return ds;
};

con.Close();
return ds;

}



public DataSet obtenerPaginasUsuario(string username)
{
DataSet ds;
int regs;
string query="exec sp_obtenerPaginasUsuario '"+username+"'";
ds=ejecuta_query(query);
regs=ds.Tables[0].Rows.Count;
if (regs==0)
{
// return some info to the front end to indicate that there is no rows
}

return ds;

}

That's all, now you have finished the midleware layer, it has only a remote procedure (function) called obtenerPaginasUsuario. this function will be called for the front end.


Now you will must write your backend logic in the sql server database.

first you must be sure that there is a database on the sql server engine, with the name that you pretend to use in the conexion string of the asp.net project. next you must be sure that inside this database there is a user account with the username and password that you are using in the conexion string.
The next step is to create the table that will store the data. this table has the following structure:

CREATE TABLE tb_pagina (
cod_pag varchar (100) ,
correlativo int ,
titulo varchar(255),
username varchar (50) ,
fecha_creacion datetime ,
fecha_modificacion datetime
)

Then you must to insert some records for testing later our app.

Then you must to create a new stored procedure with the following code:

create proc sp_obtenerPaginasUsuario(@username varchar(50))
as
begin

create table #paginas(cod_pag varchar(100),titulo varchar(255),fecha_creacion datetime,
fecha_modificacion datetime);

insert into #paginas select distinct cod_pag,titulo,fecha_creacion,fecha_modificacion
from tb_pagina where username=@username

select '0' as cod,'' as men,a.cod_pag,a.titulo,convert(varchar,a.fecha_creacion,103) as fecha_creacion,
convert(varchar,a.fecha_modificacion,103) as fecha_modificacion
from #paginas a order by convert(datetime,a.fecha_creacion)

end



you must give to the above stored procedure the permissions to get records from the database, and you must be sure that the user's account that you are using on the 'conexion' string variable is granted to execute the stored procedure.

That's all, now you finished the back end logic. now is time for test our front end:

open a web browser, and visit the Hummingbird page created, you must see something like this:


Remember that the hb_grid widget is invisible in visit mode, that's the reason why it no appears on the above image. Now click on the 'get rows' text and you will see a grid with the records retrieved from the database like showed on this image:

Great, on these posts you have learned how to access a backend, retrieve records from it, create a grid dinamically and show data on it. Remember that this is only a very simple sample and there is very much that you can make with HB.
On the next post i will show you the hb_grid widget with more details, so you will have a more complete understanding about it and how it integrates inside HB.

Have a nice day... :)

Sunday, February 20, 2011

Accessing databases with Hummingbird and scripting part I

Although Hummingbird is a powerful tool for creating content for the web, there was situations where it did not had a way to help the users. i mean to the following situation:
Suppose that you have some information stored in a server, this server is accessible for Hummingbird. you want that Hummingbird (HB) access that data in order to displaying on a page created with it, or may be you could want to get some data input from the users, and save the data entered for the users in the server.
The good news are that now HB allow you to accessing your own data stored in other servers.
HB works like a three layers architecture. watch the following image:

The above image show you the three layers that interacts in order to get or store some data on a backend (database) server. let me give you a little explanation of every of them:

1. Front end layer: this is web content (page) created with Hummingbird, it executes (run) on the client (your pc). The users interacts with it in order to get or store some kind of info from the server. The front end makes requests to the midleware passing it parameters (if necesary) in order to get or store some info from the backend.

2. Midleware layer: This acts like an intermediary between the front end and the back end, it receives the parameters from the front end, validating them, and processing the request making (if necesary) a midleware request to the backend. passing parameters (if necesary) to it., then it takes the response from the backend and prepares its response sending it to the front end. you must implement (programming) this layer, because only you know the way that the midleware will manage the data to (from) the backend server. This layer could be an asp.net app, a java app, or anything that could receive (send) remoting procedure calls (RPC).

3. Backend layer: tipically is the database logic, implemented in a database engine (sql server, my sql, oracle, etc.). When the midleware makes a request to the backend tipically it executes an stored procedure on the data base server, then the stored procedure (sp) gets the data from the database and returns them to the midleware (a request to get data), or saves some info on the server (a request to store data). You must implement this layer, let say creating the sp's, tables, and every thing necesary in order to the midleware can comunicates with the backend.

now i will show a sample that implements every one of the layers in order to make a simple database request. The request will return several rows from the database and HB will show this rows on a page in tabular way using a grid object (implemented like a widget).
For the sample we will use the following:
- For the front end we will use obviously HB.
- For the midleware we will use asp.net + fluorineFX, fluorineFX is a framework that allow to an asp.net application managing remoting procedure calls. For more info visit: http://www.fluorinefx.com/. you could use any other language supporting RPC.
- For the backend logic we will use sql server, but you could use any other database engine.

1. first we will create an HB page:
enter to HB using your account. I will use an account called database, so my first page created with this account will be called database1.
select the database1 page and press the button 'ir al diseñador' ('go to the designer' ) on the control panel.




now you are in the designer. So press the button that says 'texto' (text) to create a text object with the text 'get rows', i will use this like a button to be clicked in order to get the records, but you could use other object that responds to a click event:


Uploading a widget to the Hummingbird server

The next step is upload a widget to the HB server. i had called this widget hb_grid because it allow you to show records in a tabular way. You must upload the widget like any other widget, let say like an image, so first you must press the 'foto' (picture) button on the tools panel, and you will see:


then press the 'subir imagen' (upload image) button, you will be presented with a little window, then press the 'elejir archivos' (choose files) button and navigate to the folder where is located the swf for the widget, like showed on this image:


when you select the file for the widget you will see a button on the little window with the text 'upload', you must press on it in order to begin the upload of the widget.

When the upload is finished you must to return to the create image window and select the just uploaded widget, and press the aplicar (apply) button, like showed on this picture:



so now you will see a widget on your page that says grid widget:


This widget is visible only in desing mode, but in visit mode is invisible. we will use this widget to show the data base rows inside a grid (in tabular way).
Now we will write some scripts to get the data to be shown. go to the 'edicion' (edition) menu and choose the 'script' option. you will see the scripts window. there you must write an imports event with the following code:

import mx.controls.Alert; // used to display little messages on the page
import Connection; // needed to connect with the midleware
/*
next we create a connection object and store it in a global variable (con)
for later use
*/
global.con=page.newConnection();
// loading of the loadPolicy file in order to have acces to the remote call procedures
global.con.loadPolicyFile("http://alexaraya.cl/WebServPortalFlex/crossdomain.xml");
// open the connection to the midleware (made with asp.net)
global.con.openConnection("http://alexaraya.cl/WebServPortalFlex/Gateway.aspx");

/*
the nexts imports will allow to create a datagrid and the necesary columns to
present the data to the user
*/
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridColumn;


Like showed on this pic:


Remember that the imports event is the first in executing when a page is loaded on the client, so the above code will be executed before any other code on the page.
sure you are asking you what is the policy file. it is a file that must be located on the same directory of the asp.net application in order to give access to our front end to the remote access procedures contained on the midleware. the policy file is simply an xml file containing the following:


this file must be created for you and located in the same folder like the asp.net application.

Now we write the logic for the 'get rows' button (the onClick event):

/* when the user press the "get rows" button we execute a remote
procedure called "obtenerPaginasUsuario" that returns all the pages of
a user, on this case the name of the user is jaime
if we get a positive response from the midleware the serverResponse event
will be triggered, and if there was an error the serverError event will be triggered
*/

global.con.call("WebServPortalFlex.servicios.obtenerPaginasUsuario","serverResponse","serverError","jaime");

like i will show you in the next post , 'WebServPortalFlex' is the nameSpace in the asp.net project where is the procedure to be executed, servicios is a classname in the same asp.net project and obtenerPaginasUsuario is the name of the remote procedure (function) to be executed.

The next picture shows the onClick event for the button:

now we write the script for the response event:

/*
this event is executed when the midleware returns info succefuly.
first we convert the records into an arrayCollection object that can be used
for the grid. the records returned from the midleware are in the result
parameter
*/
var registros=page.loadArrayCollection(result.Table.serverInfo);

/* we create a datagrid using the hb_grid widget contained in
the database1_2 object (an image object)
*/
var o=page.findObject2("/database1_2");
var dg=o.content.application.new_grid();
/* now we create the columns for the datagrid */
var columns=new Array();
var c1=new DataGridColumn();
c1.dataField="cod_pag";
c1.headerText="codigo pagina";
c1.editable=false;
c1.width=100;
columns.push(c1);
var c2=new DataGridColumn();
c2.dataField="titulo";
c2.headerText="titulo";
c2.editable=false;
c2.width=300;
columns.push(c2);
dg.columns=columns; // assign the columns to our new grid
// let know to the datagrid where are the data to be used
dg.dataProvider=registros;
/* adjust some properties like the position on the page for the grid,
row height, etc.
*/
dg.x=100;dg.y=100;dg.height=500;
dg.rowHeight=30;
dg.showHeaders=true;
/*put some styles for the grid like colors for the rows,
header colors, font , etc.
*/
dg.setStyle("alternatingItemColors", [0x9999cc, 0x9999ff]);
dg.setStyle("headerColors", [0x9999ff, 0xcccccc]);
dg.setStyle("color", 0x0B333C);
dg.setStyle("rollOverColor",0xcc3366);
dg.setStyle("selectionColor", 0xcc9900);
dg.setStyle("fontFamily", "Courier");
dg.setStyle("fontSize", 11);
dg.setStyle("horizontalGridLines", true);
dg.setStyle("verticalGridLineColor", 0xffffff);
// add the datagrid to the page in order to be visible to the user
page.content.addChild(dg);


this is showed on this picture:



the last step to end our HB page is write the script for the serverError event:

Alert.show("an error ocurred on the midleware"); // shows a message to the user


like showed on this image:



That's all, now we ended our front end. The next step is create the midleware (with asp.net) and the backend logic (with sql server). I will show you the way in the next post...

Wednesday, February 9, 2011

Collaborators

follows are the collaborators of the project. If you like the project and you think that you can help it in some way, only send me an email and tell me the way you can do it.

Alberto Nudman

Alberto holds a degree in Chemical Engineering from Universidad de Chile, but has worked for the last 8 years in fields related to IT and software development. Its primary interests include software usability, interface design, and systems administration. In his spare time he likes to play with his two children and play the cello.

Contact info:
LinkedIn