14.5 Embedding Data as JavaScript Objects
NN 4, IE 4
14.5.1 Problem
You want to include data retrieved by
server processes in the JavaScript code of the page, so that client
scripts can manipulate the data and/or provide rendering options for
the user.
14.5.2 Solution
Your server processing code can insert blocks of dynamically
assembled data into portions of the HTML page about to be served to
the client. While string data is typically sent to the client as
values of hidden input elements, JavaScript data structures offer
significantly more power and flexibility once the code loads into the
client.
For simple collections of related values, JavaScript arrays are ideal
mechanisms, especially with the shortcut syntax that simplifies code
assembly on the server:
var dataArray = ["value0", "value1", "value2", ... "valueN"];
For repetitive database-record-like data, shortcut JavaScript object
creation syntax makes it a snap to define properties and their
values:
var dataObject = {prop0:"value0", prop1:"value1", prop2:"value2", ...
propN:"valueN"};
To create an array of objects, take advantage of the length of a
newly created array to get started. By using a calculated array index
value, you can modify the sequence of array entries without having to
renumber the indexes manually:
var dataArray = new Array( );
dataArray[dataArray.length] = {prop0_0:"value0_0", prop0_1:"value0_1",
prop0_2:"value0_2", ... prop0_N:"value0_N"};
dataArray[dataArray.length] = {prop1_0:"value1_0", prop1_1:"value1_1",
prop1_2:"value1_2", ... prop1_N:"value1_N"};
...
Values assignable as array items or object values can be quoted
strings (shown here), numbers, Booleans, and other arrays and
objects. In fact, there is no practical limit to the amount of
nesting you can do to create complex objects whose properties are,
themselves, complex objects.
14.5.3 Discussion
If you define the JavaScript data objects in a script within the
<head> tag, those objects are defined and
ready to go when the body starts rendering. Therefore, you have the
choice of utilizing those objects to generate dynamic HTML while the
page loads, or of using the body's
onload event handler to trigger a function that
modifies the body delivered with the page.
You don't have to embed the data formally within the
HTML page. Instead, a separate server process (invokeable via URL)
can serve as the source for the equivalent of a
.js script library. Specify the URL of the
process as the value of the <script>
tag's src attribute. Make sure
that the string content returned from the process is in the same
script-only form as any valid .js file and that
the content type for the output is
text/javascript. Because of potential
synchronization problems with a secondary server request, access the
data delivered this way via the page's
onload event handler only.
One of the most convenient JavaScript data formats is an object
utilizing string index values. These aren't arrays
per se, since the object does not gain a length
property, and iterating through its members requires the
for-in style of object introspection. A little
known fact is that JavaScript lets you build this pseudohash table on
top of an array object, and the two sets of data do not collide (as
shown in Recipe 3.9). For example, consider the following JavaScript
data variation of the World Cup final match records, delivered
initially as an array of objects:
var matchData = new Array( );
matchData[0] = {loser:"Argentina", losscore:"2", location:"Uruguay",
winner:"Uruguay", winscore:"4", year:"1930"};
matchData[1] = {loser:"Czechoslovakia", losscore:"1", location:"Italy",
winner:"Italy", winscore:"2", year:"1934"};
...
Now imagine a page that has a select element
containing a list of the years of all the matches, allowing a user to
select a year to display the details of the final match. The slow way
to reach the data is to use a for loop through the
matchData array, looking at each
year property value in search of a match of the
chosen option value. For a sizable array, this
could take a few seconds. But a one-time preprocessing of the array
can create the pseudohash table with the years as string index
values. Immediately after the matchData array is
completely populated, the following statements generate the hash
table:
for (var i = 0; i < matchData.length; i++) {
matchData["_" + matchData[i].year] = matchData[i];
}
Notice an interesting
twist that the sample data required: because the
year property values being used as hash table
indexes automatically cast to numeric values when placed in that
context, a nonnumeric value (an underscore) is concatenated onto each
value to force the index to be a string value. Otherwise, the numeric
value increases the length of the array, without generating the
string-indexed hash table. For nonnumeric property values, you can
eliminate the concatenation trick and supply just the property
reference.
Once the hash table is created, you can now reference the array
object through the unique string index of the hash table, as in this
oversimplified example:
<select onchange="alert('Winner was: ' + matchData[this.value].winner)">
<option value="_1930">1930</option>
<option value="_1934">1934</option>
...
</select>
14.5.4 See Also
Recipe 3.1 for creating arrays; Recipe 3.8 for creating custom
objects; Recipe 3.9 for generating hash tables from arrays or arrays
of objects; Recipe 3.11 for sorting arrays of objects.
|