The communication is mainly handled by the framework. This means that the framework determines which information is sent back and forth and actually makes the AJAX request. Instead of directly calling a web-service the controls tell the framework that they want call a function on the server and the framework assembles and sends the call, handles the response and notifies the control.
A server action is a call to a specific function of a web object on the server. The framework makes sure that the call is assembled and contains the current application state (synchronized web properties and rowids). The main function for doing this is available on the df.WebObject class and is inherited by all framework controls.
This method is used to send a call to the DataFlex object represented by the JavaScript object. The framework will assemble the request and send it to the server.
Parameter |
Type |
Description |
sMethod |
String |
Name of the published DataFlex function / procedure (no msg_ or get_ should be passed). |
aParams |
Array |
Array with the parameters that need to be passed to the function / procedure. |
aOptData |
Struct |
(optional) Struct of type tWebValueTree objects that can be sent as additional complex data. Pass null if no data needs to be sent. |
fOptHandler |
Function |
(optional) Handler function executed when the call is finished and a response is received. |
oOptEnv |
Object |
(optional) Object that will be the context when the handler function is called. The JavaScript this will point to this object. If no object is passed the JavaScript web object itself will become the context. |
The example below shows how to publish a function on the server. Inside a class this is usually done inside the End_Construct_Object.
Function SayHello String sTo String sFrom Returns Boolean
Send ShowInfoBox (SFormat("%1 says hi to %2", sFrom, sTo))
Function_Return True
End_Function
…
Procedure End_Construct_Object
// Publish methods....
WebPublishFunction SayHello
Forward Send End_Construct_Object
End_Procedure
Calling this function from JavaScript is done using the serverAction. The function name is passed as string and the parameters as an array. A handler function can be passed that is called when the action is completed. The handler function will be called with an event object (df.events.JSEvent) as parameter that has a property sReturnValue that contains the return value. Note that the return value is always passed as a string regardless the DataFlex type returned.
this.serverAction("SayHello", [ "the World", "John" ], null, function(oEvent){
// Executed after call has returned
if(oEvent.sReturnValue === "1"){
}
}, this);
Some controls will need to be able to pass complex sets of data to the server. Examples within the framework are the grid and treeview controls. The framework has a standard format for sending data to the server which is the tWebValueTree. Data formatted in this struct format can be passed to the server with server actions. The format is based on the existing value tree format which has the advantage that any struct can be represented in this format.
Struct tWebValueTree
String v
tWebValueTree[]c
End_Struct
In JavaScript the df.sys.vt.serialize function is able to convert any data object into a value tree. The developer himself is responsible for delivering the data in the right format. The example below shows how to add a complex set of data to a server action.
// Create data objects
var oData = {
labels : ["January","February","March","April","May","June","July"],
datasets : [{
strokeColor : "rgba(220,220,220,1)",
data : [65,59,90,81,56,55,40]
},{
strokeColor : "rgba(151,187,205,1)",
data : [28,48,40,19,96,27,100]
}]
};
// Serialize to valuetree
var tVT = df.sys.vt.serialize(oData);
// Send call to the server
this.serverAction("ProcessData", [ 2, 1 ], tVT, function(oEvent){
alert(oEvent.sReturnValue);
});
In the example above the oData object is serialized into a valuetree stored in the tVT variable. This value tree is passed to the server as the aOptData parameter of the serverAction method.
// Define the structs
Struct tActionDataSet
String strokeColor
Integer[] data
End_Struct
Struct tActionData
String[] labels
tActionDataSet[] datasets
End_Struct
// Function called as server action
Function ProcessData Integer iParam1 Integer iParam2 Returns String
tWebValueTree tVT
tActionData tData
// Retrieve and deserialize data
Get ptActionData to tVT
ValueTreeDeserializeParameter tVT to tData
Function_Return tData.labels[3]
End_Function
WebPublishFunction ProcessData
The DataFlex code above defines structs that match the format of the data sent by the client. Then the ProcessData function is defined which retrieves the value tree from the ptActionData property (that is where the WebApp Framework puts it). It deserializes the data into the struct format using the ValueTreeDeserializeParameter command. Now the data can be accessed like a regular struct / array.
The framework has some special standardized support for events. Events are basically server actions that are meant implemented by the developer using the control. So usually that would be done in the object instead of the class. The server-side event handler can be turned off using a web property for efficiency reasons and optionally the event can be implemented on the client. A web property can be set to the name of a global JavaScript function that will handle the event.
In the DataFlex class an event is defined by two web properties and a published stub procedure. The example below shows how to define an event named OnIncrement. Note that the procedure is marked as event using a meta tag so that the studio will thread it as an event. In this case the event is enabled by default.
Procedure Construct_Object
Forward Send Construct_Object
// OnIncrement event properties
{ WebProperty=True }
Property Boolean pbServerOnIncrement True
{ WebProperty=True }
Property String psClientOnIncrement ""
// Set client-side class
Set psJSClass to "Spinner"
End_Procedure
{ MethodType=Event }
Procedure OnIncrement Integer iNewValue Integer iPrevValue
// Empty event stub
End_Procedure
Procedure End_Construct_Object
Forward Send End_Construct_Object
// Publish functions called from the client
WebPublishProcedure OnIncrement
End_Procedure
On the client the event is defined in the constructor function using the event function available on df.WebObject. This function defines the properties and creates a df.events.JSHandler object for advanced client-side event handling. Then the event is fired using the fire function.
this.event("OnIncrement", df.cCallModeWait);
…
this.fire("OnIncrement", [ this.piSpinValue, iPrevValue ], function(){
// This code is executed after the server processed this event
});
[TODO: Describe call mode]
This method is used to trigger an event. It will check if the server-side event is enabled and if the client-side handlers are registered. It returns true if the event is handled on the client or the server.
Parameter |
Type |
Description |
sName |
String |
Name of the published DataFlex function / procedure. |
aParams |
Array |
Array with the parameters that need to be passed to the function / procedure. |
fOptHandler |
Function |
(optional) Handler function executed when the call is finished and a response is received. |
oOptEnv |
Object |
(optional) Object that will be the context when the handler function is called. The JavaScript this will point to this object. If no object is passed the JavaScript web object itself will become the context. |
Next to server actions the framework also knows client actions which are basically function calls on the client. Any JavaScript function available on a web object can be called. The ShowInfoBox function is an example of a client action that shows an info box. Lists and Grids also use a client action to fill themselves. In DataFlex the ClientAction procedure on cWebObject is available to perform client actions.
This method is used to call a JavaScript function on the web object. This function works asynchronous as the call is queued and added to the response.
Parameter |
Type |
Description |
sName |
String |
The name of the JavaScript function. |
aOptParams |
String[] |
Array with the parameters that need to be passed to the function. |
aOptData |
tWebValueTree |
(optional) tWebValueTree struct that can be used to send additional complex data. |
The function in JavaScript is just a regular function and no extra publishing is required. The example below shows a function that shows a standard info box in the browser using the window.alert API.
sayHello : function(sTo, sFrom){
window.alert(sFrom + " says hi to " + sTo);
},
The sample below shows how to call this function from the server-side object using the ClientAction procedure.
String[] aParams
Move "the World" to aParams[0]
Move "John" to aParams[1]
Send ClientAction "sayHello" aParams
Similar to server actions it is also possible to complex sets of data to client actions. This is also done using the tWebValueTree format. The value tree can be passed as the third parameter of the ClientAction procedure.
// Define the structs
Struct tActionDataSet
String strokeColor
Integer[] data
End_Struct
Struct tActionData
String[] labels
tActionDataSet[] datasets
End_Struct
// Send the client action
String[] aParams
tWebValueTree tVT
tActionData tData
// Generate some data
Move "Januari" to tData.labels[0]
Move "Februari" to tData.labels[1]
Move "#FF0000" to tData.datasets[0].strokeColor
Move 55 to tData.datasets[0].data[0]
Move 88 to tData.datasets[0].data[0]
// Serialize to a value tree
ValueTreeSerializeParameter tData to tVT
// Call the client action
Send ClientAction "processData" aParams tVT
The DataFlex code above shows the entire process of defining a struct, filling it and sending it to the client. Note that the ValueTreeSerializeParameter command is used to serialize the struct into a value tree.
// Define the struct format used by the deserializer
var tActionDataFormat = {
labels : [ df.tString ],
datasets : [{
strokeColor : df.tString,
data : [ df.tInt ]
}]
};
// Client action called with action data
processData : function(){
var tData, tVT;
// Retrieve value tree and deserialize
tVT = this._tActionData;
tData = df.sys.vt.deserialize(tVT, tActionDataFormat);
// Do something with the data
alert(tData.labels[1]);
},
The sample code above shows how to handle this data in JavaScript. It starts by defining the structure of the data it receives. As the value tree only contains the data the deserializer needs the format to bring the data back to a readable format. The value tree is made available by the framework under the this._tActionData property. We use the df.sys.vt.deserialize function to deserialize the value tree into usable data objects.
Previous Topic: Web Properties
Next Topic: Control Template