Example: a dynamic shopping cart



The following example dynamically creates and manipulates variable names without using dynamic expression evaluation by using associative array notation.

You need to dynamically generate variable names in applications such as shopping carts, where the required output is dynamically generated and variable. In a shopping cart, you do not know in advance the number of cart entries or their contents. Also, because you are using a form, the action page only receives Form variables with the names and values of the form fields.

The following example shows the shopping cart contents and lets you edit your order and submit it. To simplify things, the example automatically generates the shopping cart contents using CFScript instead of having the user fill the cart. A more complete example would populate a shopping cart as the user selected items. Similarly, the example omits all business logic for committing and making the order.

Create the form

  1. Create a file in your editor.

    <html> 
    <head> 
        <title>Shopping Cart</title> 
    </head> 
    <cfscript> 
    CartItems=4; 
    Cart = ArrayNew(1); 
    for ( i=1; i LE cartItems; i=i+1) 
    {  
        Cart[i]=StructNew(); 
        Cart[i].ID=i; 
        Cart[i].Name="Product " & i; 
        Cart[i].SKU=i*100+(2*i*10)+(3*i); 
        Cart[i].Qty=3*i-2; 
    } 
    </cfscript> 
     
    <body> 
    Your shopping cart has the following items.<br> 
    You can change your order quantities.<br> 
    If you don't want any item, clear the item's check box.<br> 
    When you are ready to order, click submit.<br> 
    <br> 
    <cfform name="ShoppingCart" action="ShoppingCartAction.cfm" method="post"> 
    <table> 
        <tr> 
        <td>Order?</td> 
        <td>Product</td> 
        <td>Code</td> 
        <td>Quantity</td> 
        </tr> 
        <cfloop index="i" from="1" to="#cartItems#"> 
            <tr> 
            <cfset productName= "product_" & Cart[i].ID> 
            <cfset skuName= "sku_" & Cart[i].ID> 
            <cfset qtyname= "qty_" & Cart[i].ID> 
            <td><cfinput type="checkbox" name="itemID" value="#Cart[i].ID#" checked> 
                 </td> 
            <td><cfinput type="text" name="#productName#" value="#Cart[i].Name#" 
                 passThrough = "readonly = 'True'"></td> 
            <td><cfinput type="text" name="#skuName#" value="#Cart[i].SKU#" 
                 passThrough = "readonly = 'True'"></td> 
            <td><cfinput type="text" name="#qtyName#" value="#Cart[i].Qty#"> 
                 </td> 
            </tr> 
        </cfloop> 
    </table> 
    <input type="submit" name="submit" value="submit"> 
    </cfform> 
     
    </body> 
    </html>
  2. Save the file as ShoppingCartForm.cfm.

Reviewing the code

The following table describes the code:

Code

Description

<cfscript> 
CartItems=4; 
Cart = ArrayNew(1); 
for ( i=1; i LE cartItems; i=i+1) 
{  
    Cart[i]=StructNew(); 
    Cart[i].ID=i; 
    Cart[i].Name="Product " & i; 
    Cart[i].SKU=i*100+(2*i*10)+(3*i); 
    Cart[i].Qty=3*i-2; 
} 
</cfscript>

Create a shopping cart as an array of structures, with each structure containing the cart item ID, product name, SKU number, and quantity ordered for one item in the cart. Populate the shopping cart by looping CartItems times and setting the structure variables to arbitrary values based on the loop counter. A real application would set the Name, SKU, and Quantity values on other pages.

<cfform name="ShoppingCart" action="ShoppingCartAction.cfm" method="post"> 
<table> 
    <tr> 
    <td>Order?</td> 
    <td>Product</td> 
    <td>Code</td> 
    <td>Quantity</td> 
    </tr>

Start the form and its embedded table. When the user clicks the submit button, post the form data to the ShoppingCartAction.cfm page.

The table formats the form neatly. The first table row contains the column headers. Each following row has the data for one cart item.

    <cfloop index="i" from="1" to="#cartItems#"> 
        <tr> 
        <cfset productName= "product_" & Cart[i].ID> 
        <cfset skuName= "sku_" & Cart[i].ID> 
        <cfset qtyname= "qty_" & Cart[i].ID> 
        <td><cfinput type="checkbox" name="itemID" value="#Cart[i].ID#" checked> 
             </td> 
        <td><cfinput type="text" name="#productName#" value="#Cart[i].Name#" 
             passThrough = "readonly = 'True'"></td> 
        <td><cfinput type="text" name="#skuName#" value="#Cart[i].SKU#" 
             passThrough = "readonly = 'True'"></td> 
        <td><cfinput type="text" name="#qtyName#" value="#Cart[i].Qty#"> 
             </td> 
        </tr> 
    </cfloop> 
</table>

Loop through the shopping cart entries to generate the cart form dynamically. For each loop, generate variables used for the form field name attributes by appending the cart item ID (Cart[i].ID) to a field type identifier, such as "sku_".

Use a single name, "itemID", for all check boxes. This way, the itemID value posted to the action page is a list of all the check box field values. The check box field value for each item is the cart item ID.

Each column in a row contains a field for a cart item structure entry. The passthrough attribute sets the product name and SKU fields to read only; note the use of single-quotation marks. (For more information on the cfinput tag passthrough attribute, see the CFML Reference.) The check boxes are selected by default.

<input type="submit" name="submit" value="submit"> 
</cfform> 

Create the Submit button and end the form.

Create the Action page

  1. Create a file in your editor.

  2. Enter the following text:

    <html> 
    <head> 
        <title>Your Order</title> 
    </head> 
    <body> 
    <cfif isDefined("Form.submit")> 
        <cfparam name="Form.itemID" default=""> 
        <cfoutput> 
            You have ordered the following items:<br> 
            <br> 
            <cfloop index="i" list="#Form.itemID#"> 
                ProductName: #Form["product_" & i]#<br> 
                Product Code: #Form["sku_" & i]#<br> 
                Quantity: #Form["qty_" & i]#<br> 
                <br> 
            </cfloop> 
        </cfoutput> 
    </cfif> 
    </body> 
    </html>
  3. Save the file as ShoppingCartAction.cfm

  4. Open ShoppingCartform.cfm in your browser, change the check box and quantity values, and click Submit.

Reviewing the code

The following table describes the code:

Code

Description

<cfif isDefined("Form.submit")>

Run the CFML on this page only if it is called by submitting a form. This is not needed if the form and action pages are separate, but is required if the form and action page were one ColdFusion page.

<cfparam name="Form.itemID" default="">

Set the default Form.itemID to the empty string. This prevents ColdFusion from displaying an error if the user clears all check boxes before submitting the form (so no product IDs are submitted).

<cfoutput> 
You have ordered the following items:<br> 
<br> 
<cfloop index="i" list="#Form.itemID#"> 
ProductName: #Form["product_" & i]#<br> 
Product Code: #Form["sku_" & i]#<br> 
Quantity: #Form["qty_" & i]#<br> 
<br> 
</cfloop> 
</cfoutput> 
</cfif>

Display the name, SKU number, and quantity for each ordered item.

The form page posts Form.itemID as a list containing the value attributes of all the check boxes. These attributes contain the shopping cart item IDs for the selected cart items. Use the list values to index a loop that outputs each ordered item.

Use associative array notation to access the Form scope as a structure and use expressions in the array indexes to construct the form variable names. The expressions consist of a string containing the field name’s field type prefix (for example, "sku_"), concatenated with the variable i, which contains the shopping cart ItemID number (which is also the loop index variable).