Sie sind auf Seite 1von 8

Resin Mix Application Documentation

Database
The resin mix application uses a MySQL database on isasrvr called resin. resin consists of the tables
“component”, “product”, and “batch”.

component
Every resin mixed at OECO consists of one or more components. Many components are used in more than
one resin. The component table contains data pertaining to each resin component.

component create script:


DROP TABLE IF EXISTS `resin`.`component`;
CREATE TABLE `resin`.`component` (
`pn` varchar(12) NOT NULL,
`pic_pn` varchar(45) default NULL,
`name` varchar(45) NOT NULL,
`full_name` varchar(100) NOT NULL,
`sl` varchar(100) NOT NULL,
PRIMARY KEY (`pn`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

product
“product” contains each resin and information that is useful to the user when he or she mixes the resin.

product create script:


DROP TABLE IF EXISTS `resin`.`product`;
CREATE TABLE `resin`.`product` (
`id` int(10) unsigned NOT NULL auto_increment,
`part_num` varchar(100) default NULL,
`oeco_pn` varchar(100) default NULL,
`name` varchar(100) default NULL,
`hardness` varchar(100) default NULL,
`sc` varchar(100) default NULL,
`op_temp_c` varchar(100) default NULL,
`spec_rng_min` varchar(100) default NULL,
`spec_rng_max` varchar(100) default NULL,
`note` tinytext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
recipe
“recipe” is basically a junction table that tells which components are in which resins in what amounts.

recipe create script:


DROP TABLE IF EXISTS `resin`.`recipe`;
CREATE TABLE `resin`.`recipe` (
`id` int(10) unsigned NOT NULL auto_increment,
`prod_id` varchar(45) default NULL,
`component` varchar(45) default NULL,
`amt` varchar(45) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Web Components
Overview
The resin mix application, like the MSDS database app, is built on MySQL and ColdFusion. In addition the
resin mix application makes heavy use of JavaScript and of an AJAX framework for ColdFusion called
ajaxCFC.

The primary purpose of the resin mix application is to aid OECO associates in the mixing of resins. It does
this by taking a resin number and desired weight of resin and outputting a list of components that should
be mixed to make the resin along with the amount of each component to mix to make the desired weight
of the resin. As an added benefit, the application provides of means of tracking batches of resin made
using it. In order to support these two core functions, we also created a number of pages for updating the
database and querying it for batch history.

Home
The application’s start page, index.cfm, contains only one form, The Resin Mix Formula Sheet. The Resin
Mix Formula Sheet takes three pieces of information from the user; the employee number of the user, the
resin number of the resin to be mixed, and the weight of resin to be mixed. The user types his or her
employee number into the employee number input box. If the employee number is valid (if it is found in
the database), the employee name box populates with the corresponding employee name. The resin
number goes into the box labeled “Resin Number (OECO)”. An example of a resin number is “R-283” or “R-
290-3”. When a valid resin number is entered, information corresponding to that resin appears in the box
labeled “Mfgrs Description”. In addition, a list of components required to make this resin appears in the
table in the middle of the form with the headers “Component”, “PN”, and “Amount (grams)”. If a weight
for the resin batch has already been input, then the weight of each component will appear in the “Amount
(grams)” column. If not, these weights will appear once the user types a number into the box labeled
“Weight Required (grams)”.

Once the Resin Mix Formula Sheet has been filled out, the user can save it to the batch history by clicking
“Save” to submit the form to a page called batch.cfm which updates the database with the batch
information. The formula sheet will only submit the form if all three inputs (employee number, resin
number, and weight) are valid. An input is valid if the form elements or elements with which it is
associated are updated when it is entered. For example a valid employee number is one that causes an
employee name to appear in the employee name box when the user types it in the employee number box.
Once a batch has been saved, it’s record can be accessed using the “history” portion of the application.

Resins
The “Resin Management” page, resin.cfm, is designed to allow an administrative user to add, edit, and
remove resin mixes from the database. It’s main form, “Resin Mix Details” is used for all three of these
functions. By default, this form is blank. To add a resin mix, the user simply types in the pertinent
information in the boxes. A component is added to the resin mix’s “recipe” by clicking the button labeled
“Add a Component” and filling in the form elements that appear. Changing a component’s PN in its drop -
down list causes the corresponding component name to appear in the box below it.

When resin.cfm loads, it checks for an optional resin mix number argument in the URL. When this
argument is present, it queries the resin table in the database for a resin mix record with a matching resin
mix number and displays the data from that record in the appropriate input boxes. resin.cfm also queries
the recipe table and loops through the records of the corresponding recipe result set, creating and
populating a set of input boxes for each component inside its own table. In addition, it creates a number
of tables with their display property set to “none”. These are the form elements that appear when the
“Add a Component” button is clicked.

When the user is ready save the resin mix, he or she clicks the “Save” button. This triggers a validation
function that checks to make sure that (1) a resin mix number has been entered, (2) at least one
component has been entered, (3) every component has a value in its “amount” box, and (4) the value for
every component’s amount is a number. The last two validation steps are only performed on components
whose parent table elements (e.g. “myTable_1”) have their display property set to “block” and thus have
been displayed to the user for editing. When all the validation criteria have been satisfied, a function is
called that checks to see whether or not the value in the resin mix number box belongs to a record already
in the database. If it does, the user is prompted as to whether or not they want to overwrite the existing
record, if not, a new record is created for the resin mix.

To clear the resin mix form, the user clicks “Reset”. This directs them to the default “resin.cfm” page with
all of the input boxes empty and all of the components empty and hidden. If the user clicks “Cancel”, he or
she is directed to index.cfm.

In addition to the Resin Mix Details form, resin.cfm also contains two other parts; a resin search and a list
of recent batches. The resin search is modeled after and operates in much the same fashion as the MSDS
search. When search criteria are entered and submitted, the resulting query results are presented in rows
in a new page. Each row is linked back to the resin.cfm with the corresponding record’s resin mix number
as an argument in the link URL. When a row is clicked, its record’s information is loaded in the resin.cfm
input boxes. The list of recent batches contains rows that contain less information but are of the same
nature.
Components
In case a resin component in needed that is not already in the database, or the information for a particular
component needs updated, we have included component.cfm to allow users to make changes. The drop-
down box next to “PN”, PNSelect, contains a list of every resin in the system that it gets dynamically when
the page loads. At the end of the list is an option labeled, “other, please specify:”. When this opti on is
selected, a box (PNBox) appears beneath it to accept a new PN for a component and the other three boxes
are cleared. Otherwise, an ajaxCFC query loads record information on whichever PN is selected in
PNSelect. The button labeled “Add a new component” is a jury rig. All it does is set PNSelect to “other,
please specify:”, thus triggering the function to clear the other boxes.

Like the components page, the resins page can take an argument in the URL on which to query and fill the
boxes with the query results:

http://127.0.0.1:8500/resin/component.cfm?PN=451%2D00825%2D03

This is how links are constructed for component search results and recent changes. These two
components (search and recent) work the same way as in the resins section.

History
The history section contains a copy of the form seen in the home section with the “readonly” attribute set
for every input box. Thus, it is only for recalling information from old batches, and not for editing them. A
record is recalled by supplying the page with a record ID (aka batch ID) as in argument in the URL:

http://127.0.0.1:8500/resin/history.cfm?ID=12

In addition to simply typing the record number after “ID=” in the URL, there are three other ways of
loading a record. For one, the user can type the number into the box next to the button labeled “Load
Record” and click “Load Record”. For another, he or she can use the batch search and click one of the links
that appears in the search results, and lastly, he or she can click one of the links in the list of rece nt
batches.

Technical Notes
Queries with ajaxCFC and JavaScript
You may have noticed that most input tags in the various pages of the resin mix application have no
“value” attribute. This is because they get their values from JavaScript functions that in turn use ajaxCFC to
query the database and return values. As such, the user is given immediate feedback based on his or her
input. This is accomplished by making CFCs that extend a special CFC called ajax.cfc and invoking them
with a Direct Web Remoting (DWR) engine. Here’s how it works:

1. The user types in a field.


ex: Charles Thompson types his employee number into the input “emp_num”.
2. The field’s “onpropertychange” event fires, calling the JavaScript function indicated in its
onpropertychange element.
ex: emp_num’s onpropertychange fires, calling the function “employeeQuery”.

3. The function calls the “_execute” method of the DWR engine with the user’s input as an
argument.
ex: employeeQuery calls DWREngine._execute with Charles’ employee number as an argument.

4. The DWR engine invokes a CFC (also in its arguments) that runs the query on the input.
ex: DWREngine._execute invokes query.cfc which runs this query:
select * from employee
where id = '[Charles’ employee number]'

5. The DWR engine calls a callback function that takes “r” as an argument. The object, “r” contains
results of the query.
ex: The DWR engine calls “employeeQueryResults”

6. The callback function populates related fields with the query results using the Document Object
Model (DOM) or one or more built-in DWR utilities.
ex: employeeQueryResults sets the value of “emp_name” to a string containing the first and last
name found in the record matching the number input by Charles and supplied to the query.

Using the DWR Engine


DWREngine._execute has pre-defined arguments that are outlined in the ajaxCFC documentation as
follows:
DWREngine._execute(_ajaxConfig._cfscriptLocation, null, 'method', args1, args2, args3, callBackFunction);

‘_execute’ takes three or more arguments:


1st: path to listener CFC that contains the method you need to call
2nd: scriptName to execute; this argument will be null 99% of the times.
3rd: methodName; this is the function inside the CFC you want to execute.
4th: arguments; you may pass one or more arguments to the ColdFusion functi on. You can add additional
arguments as needed. These arguments are optional.
5th: Call-back function; ajaxCFC will check if the very last argument is a function will asynchronously (by
default) call that function after resolving the ColdFusion function and getting back a result.

Return Types
In addition, ajaxCFC supports a number of return types. The two return types used in the resin mix app are
structure and query returns. An example of a structure is seen in the case of emp_num/emp_name. In this
example, the function “employeeQuery” in query.cfc queries the employee database and creates a
ColdFusion structure, “mystruct” in which it stores the query results:

<cfset mystruct = StructNew()>


<cfset mystruct.first_name = #qReturn.first_name#>
<cfset mystruct.last_name = #qReturn.last_name#>
When this structure is returned to employeeQueryResults in index.cfm, its members are easily referenced
with the names assigned them in employeeQuery:

function employeeQueryResults (r) {


var full_name = r.last_name + ', ' + r.first_name
if(full_name != ', '){
document.frmResin.emp_name.value = full_name;
}
else {
document.frmResin.emp_name.value = "";
}
}

While practical and useful for queries that return only one record, structure assignment is inconvenient
when dealing with several rows. When querying the “recipe” table for a list of resin ingredients, rather
than make a structure member for every part of every row returned, we chose instead to simply return
the query itself.

<cfquery name="qReturn" datasource="resin">


Select recipe.amt as amt, component.name as component, component.pn
as pn
from recipe, component
where recipe.component = component.pn
and recipe.prod_id = '#resin_num#'
</cfquery>
<cfreturn qReturn>

When returned to “getRecipeResults”, the query result is represented in JavaScript as an object containing
an array for each column. Thus, a query representing the recipe for the resin R-283, having two rows and
three columns:

amt component pn
9 DEVCON F BASE 451-00003-07
1 DEVCON F HARDENER 451-00003-08

Takes the following form in JavaScript:

am t [array]
array

0 [string] 9
1 [string] 1

component [array]
array

0 [string] DEVCO N F BASE


1 [string] DEVCO N F HAR DENER

pn [array]
array

0 [string] 451-00003-07
1 [string] 451-00003-08
Cell references are then constructed with the general form r.column[n] where column is the name of the
column in the result set that you wish to reference and n is the number of the row. For example
r.component*1+ has the value “DEVCON F HARDENER”.

Once a query has been retrieved from the database and returned to the callback function, there are a
number of ways in which it can be put in the page for presentation to the user. One method of doing this,
which we’ve already described involves using the DOM directly to assign result set field values to page
elements such as “emp_name”. Another way to present the user with query results is to use one of the
DWR utilities. A DWR utility that works particularly well for processing query results of a varying number
of rows (such as the results of a recipe query) is addRows.

addRows
The addRows utility is called inside the callback function of an ajaxCFC query.

It follows this format:


addRows(id, array, cellfuncs, [options])

Its argument are:


id: The id of the table element (preferably a tbody element)
array: Array (or object from DWR 1.1) containing one entry for each row in the updated table
cellfuncs: An array of functions (one per column) for extracting cell data from the passed row data
options: An object containing various options
addRows is used in index.cfm like so:

DWRUtil.addRows("tableBody", r, [getComponent, getPN, getAmount], null);

addRows loops through the query results and displays cells in the columns specified in the “cellfuncs”
arguments for each row. The “cellfuncs” variables are the ones enclosed in brackets above. They refer to
functions that retrieve the value in a certain column for the current iteration of the loop. A typical bare
bones one of these looks like this:

var getComponent = function (thisRow) {


return thisRow.component;
}

If necessary, you can perform arithmetic within the function. For example in getAmount, we translate the
amount from a rational amount to the actual amount to be used in the mix:

var getAmount = function (thisRow) {


var Parts = thisRow.amt/componentSum;
var Weight = parseInt(document.frmResin.weight.value);
var Amount = Parts*Weight;
if(isNaN(Amount.toFixed(2))){
return "";
}
else{
return (Amount.toFixed(2));
}
}
The argument “tableBody” refers to the page element—in this case a tbody element—that takes the
output of addRows:

<table>
<thead>
<th><br><br>Component</th>
<th><br><br>PN</th>
<th><br><br>Amount (grams)</th>
</thead>
<tbody id="tableBody"></tbody>
</table>

A good reference for addRows can be found here: http://getahead.org/dwr/browser/addRows. Also, for
further reading on DWR in general, visit http://getahead.org/dwr.

Development\Troubleshooting Tips
In JavaScript, a useful way to see variable’s value or to test whether a code block is executing is to use the
built-in function “alert”. Alert simply takes an argument and displays its value in a dialog box with an “OK”
button to dismiss it. You can read more about it here: http://en.wikipedia.org/wiki/Alert_dialog_box.

Another tool that was indispensible while developing this site was a little JavaScript module called “dump”
that gives you the options of dumping from JavaScript in much the same fashion as cfdump. “cfdump” is a
ColdFusion tag that prints to the screen the value of a variable specified in its attribute “var”. To use it,
simply download it here: http://www.netgrow.com.au/files/javascript_dump.cfm, include it in the head
portion of your cfm or html file:

<script type='text/javascript' src="../js/dump.js"></script>

And then call it anywhere in your script with the line:

dump(variableToBeDumped);

This was particularly helpful when checking query results in returns to ajaxCFC callback functions by typing
“dump(r);” before any other line inside the function.

Finally, a good way to debug JavaScript is with the Error Console in Firefox. To access this, click Tools >
Error Console in Firefox’s menu bar. If you click “Clear” and then load the page you’re debugging or
interact with form elements, the Error Console displays a list of any errors that result. Keep in mind while
using this that Firefox and Internet Explorer behave differently and will not always have the same errors.
For example, Firefox does not recognize the “onpropertychange” event, and as such it will not display
errors associated with this event.

Das könnte Ihnen auch gefallen