Custom Values in the 4D Ajax Framework
This example demonstrates how to use custom values in the 4D Ajax Framework. The custom
value data is sent from the web page (frontend) and recieved in the 4D Database (backend).
The 4D Database (backend) then performs a query and sends custom values back to the web
page (frontend) which then formats the data and displays it on the web page. The example
is in the form of a Car Dealership's internal quoting system; it is designed to let the
user configure a vehicle with the options they want, and displays the total price on the
page.
Brands
The Brands grid displays a list of car makers in the database.
Models
The Models grid displays a list of car models in the database. The grid is initially
loaded with a bogus query to limit the display to zero results. Each time a brand is
clicked, the database is queried and the Models grid is updated to display only the models
found for the selected brand.
Options
The Options div displays a list of options (and their associated price) found in the
database for the car model selected. The div is dynamically altered each time the user
clicks on the Brands or Models grid.
Populating Data
The grids are populated with the following configuration:
Brands grid setup:
JavaScript Code:
var BrandsGrid = new dax_dataGrid('Brands',$('CarBrandDiv'), 0, 0, false);
BrandsGrid.go(); // go
BrandsGrid.disableAutoRefresh(); // disable auto refreshing the grid
BrandsGrid.hideColumn(0); // ID column
BrandsGrid.setColumnWidth(1,80); // Name
BrandsGrid.onDataRowClick = BrandClicked; // call BrandClicked on row click
End JavaScript Code
Models grid setup:
JavaScript Code:
var ModelsGrid = new dax_dataGrid('Models',$('CarModelsDiv'), 0, 0, false);
ModelsGrid.go(); // go
ModelsGrid.disableAutoRefresh(); // disable auto refreshing the grid
ModelsGrid.setColumnWidth(0,110); // Model Name
ModelsGrid.hideColumn(1); // model ID
ModelsGrid.newQuery(); //start a new query
ModelsGrid.addQuery('brandID', '=', 0); // query to get 0 results
ModelsGrid.runQuery(); // run the query
ModelsGrid.onDataRowClick = ModelClicked; // set on clicked event
End JavaScript Code
Click Events
The following functions are triggered when the Brands and Models data grid are clicked:
BrandClicked() function definition:
JavaScript Code:
function BrandClicked(row, column, recordId, fieldReference){
$totalPrice = 0;
$lastColorPrice = 0;
$('CarOptionsDiv').innerHTML = "Please select a model";
var BrandID = BrandsGrid.getCellValue(row, 0); // get field 0 value of selected row
ModelsGrid.newQuery(); // start a new query
ModelsGrid.addQuery('brandID', '=', BrandID); // Query based on BrandID
ModelsGrid.runQuery(); // run the query
} // end BrandClicked
End JavaScript Code
ModelClicked() function definition:
JavaScript Code:
function ModelClicked(row, column, recordId, fieldReference){
$totalPrice = 0;
$lastColorPrice = 0;
$('CarOptionsDiv').innerHTML = "Getting options from backend";
var ModelID = ModelsGrid.getCellValue(row, 1); // get cell value from field 3 of the selected row
prepOptions(ModelID);
} //end ModelClicked
End JavaScript Code
Sending Custom Values to the backend
The ModelClicked() function calls the prepOptions() function that will send the custom values to the backend:
PrepOptions() function definition:
JavaScript Code:
function prepOptions(modelID){
myQuery = new dax_query('Models');
myQuery.clearCustomValues();
myQuery.addCustomValue('modelID', modelID);
myQuery.handler = getOptionValues;
myQuery.runQuery();
} // end prepOptions
End JavaScript Code
Recieving the Custom Values in the backend
The DAX_DevHook_OnQuery project method will be called upon 4D receiving the custom values:
DAX_DevHook_OnQuery method (custom modification in BOLD):
4D Code:
C_LONGINT($1;$selectionNumber_l;$size_l;$i)
C_POINTER($2;$3;$4;$5;$6;$tableNumbers_p;$fieldNumbers_p;$queryValues_p;$queryComparators_p;$queryLineLinks_p)
C_BOOLEAN($7;$0;$queryInSelection_b;$queryDone_b)
C_TEXT($tableName_t;$selectionName_t;$operator_t;$value_t)
C_POINTER($table_p;$field_p)
` variable declarations for modelID custom value query
C_TEXT($modelID_t;$colorsSpan_t)
C_LONGINT($modelCount_li;$i;$colorCount_li)
C_REAL($basePrice_r)
` end variable declarations for modelID custom values query
$selectionNumber_l:=$1
$tableNumbers_p:=$2
$fieldNumbers_p:=$3
$queryValues_p:=$4
$queryComparators_p:=$5
$queryLineLinks_p:=$6
$queryInSelection_b:=$7
$queryDone_b:=False ` Change to True if you handle the Query
` *** This is an advanced feature - you'll need to be comfortable with building complex
` queries using pointers and text values
` *** To handle the queries yourself
` Convert the passed parameters to tables, fields, and values, and perform the queries
$modelID_t:=DAX_Dev_GetWebVar ("modelID")
If ($modelID_t#"")
$queryDone_b:=True
ALL RECORDS([Options])
QUERY([Options];[Options]modelID=$modelID_t)
$modelCount_li:=Records in selection([Options])
ARRAY TEXT(customVarName_at;($modelCount_li+2))
ARRAY TEXT(customVarValue_at;($modelCount_li+2))
ALL RECORDS([Models])
QUERY([Models];[Models]ID=$modelID_t)
$basePrice_r:=[Models]basePrice
customVarName_at{1}:="Base Price"
customVarValue_at{1}:=String($basePrice_r)
FIRST RECORD([Options])
For ($i;1;$modelCount_li)
customVarName_at{($i+1)}:=[Options]name
customVarValue_at{($i+1)}:=String([Options]price)
NEXT RECORD([Options])
End for
` compose HTML for colors and send as name="Colors" and value="composedHTML"
ALL RECORDS([Colors])
QUERY([Colors];[Colors]modelID=$modelID_t)
$colorCount_li:=Records in selection([Colors])
FIRST RECORD([Colors])
$colorsSpan_t:="<table border=0 cellpadding=0 cellspacing=0 border=0 width=100%>\r"
$colorsSpan_t:=$colorsSpan_t+"<tr><td rowspan="+String($colorCount_li+1)+" valign=top align=left>Colors:</td></tr>"
For ($x;1;$colorCount_li)
If ([Colors]Color="White")
$colorsSpan_t:=$colorsSpan_t+"<tr><td align=left><input type=\"radio\" id=\"White\" checked=true onclick=\"calcColor(this);\" value=\""+String([Colors]Price)+"\" name=\"color\">"+[Colors]Color+"</td><td align=right>$"+String([Colors]Price)+"</td></tr>\r"
Else
$colorsSpan_t:=$colorsSpan_t+"<tr><td align=left><input type=\"radio\" onclick=\"calcColor(this);\" value=\""+String([Colors]Price)+"\" name=\"color\">"+[Colors]Color+"</td><td align=right>$"+String([Colors]Price)+"</td></tr>\r"
End if
NEXT RECORD([Colors])
End for
$colorsSpan_t:=$colorsSpan_t+"</table>"
customVarName_at{($modelCount_li+2)}:="Colors"
customVarValue_at{($modelCount_li+2)}:=$colorsSpan_t
DAX_Dev_SetCustomVariables (->customVarName_at;->customVarValue_at)
End if
+If (False)
End if
` *** Return True if you have performed the query
` Return False to have 4DAF perform the query
$0:=$queryDone_b
End 4D Code
receiving the Custom Values callback from the backend
The getOptionsValues() function was previously set as the handler for the myQuery object that was used to send the custom values to the
backend; this is the fucntion that is called when the data comes back from 4D to the frontend:
getOptionValues() function definition:
JavaScript Code:
function getOptionValues(){
myCustomValues = myQuery.getCustomValuesFrom4D();
var len = myCustomValues.length;
if(len!=0){
$optionsHTML = "<form><table border=0 cellspacing=0 cellpadding=0 width=100%>\r";
for(var i = 0; i<len;i++){
if(myCustomValues[i].name == "Base Price"){
$basePrice=myCustomValues[i].value;
$optionsHTML = $optionsHTML + "<tr><td style=\"padding: 3px\">Base Price:</td>\r<td align=right style=\"padding: 3px\">$"+ $basePrice +"</td></tr>\r";
$optionsHTML = $optionsHTML + "<tr height=1 bgcolor=#000000><td colspan=2></td></tr>\r";
}else{ // end if / start else
$name = myCustomValues[i].name;
$value = myCustomValues[i].value;
if($name=="Colors"){
$spanForColors = $value;
}else{ // end COLOR
$optionsHTML = $optionsHTML + "<tr>\r";
$optionsHTML = $optionsHTML + "<td><input type=checkbox value=\""+ $value +"\" ID=\"DaxCarOption\" name=\""+ $name +"\" onclick=\"calcTotal(this);\">"+ $name +"</td>\r";
$optionsHTML = $optionsHTML + "<td align=right style=\"padding: 3px\">$"+ $value +"</td>\r";
$optionsHTML = $optionsHTML + "</tr>\r";
} // end COLOR else
} // end BASE PRICE else
} // end for loop
$optionsHTML = $optionsHTML + "<tr height=1 bgcolor=#000000><td colspan=2></td></tr>\r";
$optionsHTML = $optionsHTML + "<tr><td valign=top colspan=2 style=\"padding: 3px\"><span ID=\"ColorsDropDown\"></span></td></tr>\r";
$optionsHTML = $optionsHTML + "<tr height=1 bgcolor=#000000><td colspan=2></td></tr>\r";
$optionsHTML = $optionsHTML + "<tr><td><b style=\"padding: 3px\">Total Price:</b></td>\r<td align=right style=\"padding: 3px\"><b><div ID=\"TotalPrice\"></div></b></td></tr>\r";
$optionsHTML = $optionsHTML + "</table>\r</form>";
$('CarOptionsDiv').innerHTML = $optionsHTML;
$('ColorsDropDown').innerHTML = $spanForColors;
$totalPrice = $basePrice;
$('TotalPrice').innerHTML = "$"+$totalPrice;
$('White').click();
} // end IF len # 0
} // end getOptionValues
End JavaScript Code
Calculating the total cost
Each time the user clicks on any of the options, the following functions are used to calculate
the total cost:
calcTotal function definition:
JavaScript Code:
function calcTotal(item){
if(item.checked==true){
$totalPrice = parseInt($totalPrice) + parseInt(item.value);
$('TotalPrice').innerHTML = "$"+$totalPrice;
}else{
$totalPrice = parseInt($totalPrice) - parseInt(item.value);
$('TotalPrice').innerHTML = "$"+$totalPrice;
}
}
End JavaScript Code
calcColor function definition:
JavaScript Code:
function calcColor(item){
$totalPrice = parseInt($totalPrice) + parseInt(item.value) - parseInt($lastColorPrice);
$('TotalPrice').innerHTML = "$"+$totalPrice;
$lastColorPrice = parseInt(item.value); // update the price of the last color used for the next calculation
}
End JavaScript Code