Accessibility

ColdFusion Article

 

The Real Estate Sample Application – Part 2: Managing Property Listings Through Flash Forms


Table of Contents

Populating the Edit Form

The bottom right panel contains a form with an input for every attribute of a property listing: address, price, number of bedrooms, bathrooms, amenities, and so forth. Most of the fields are text input fields, but there are also controls for selects, radio buttons, check boxes, a text area, and a date field.

When a user opens the application (you can try it by going to http://localhost:8500/realestate/index.cfm), he or she selects search criteria and the application returns the search results. The user clicks one of the records in the datagrid and expects the detail panel in the bottom right corner to display the details of the selected record. Where will the necessary information come from?

In Part 1 of this tutorial, the search returned query results that contained all of the columns in the "listing" table in the database. However, only a few of those columns—namely Price, Type, Bedrooms, Bathrooms, and Footage—appeared in the datagrid.

"What a waste of bandwidth!" you may have thought. Not really so, because you will need the additional columns to populate the entire form.

You will populate each field from a column of the query returned by the search. The query that populates the datagrid is "stored" in the datagrid. To get the data corresponding to the selected row in the grid, you will access the cfgrid by its name (listingGrid) and its special property (selectedItem); the name and property specify the row the user selected.

Then, with dot notation, you select the specific column you need, which is different for each input. The complete path is this: listingGrid.selectedItem.columnName. Use this path for all of the columns of the query, even if they were not defined as datagrid columns with the cfgridcolumn tag.

Binding Each Field Type

Now that you know how to get the data for each property listing attribute, you are ready to display it. Just below the search results, you will add a new panel (note that Part 1's sample files already contain this panel) that contains the add/edit form:

<cfformgroup type="panel" label="Add / Edit Properties">
</cfformgroup>

Within this panel, you will add—one by one—all the fields corresponding to each property listing attribute, such as address, number of bedrooms, and so forth. Each field has a different length or type, so you will use different controls or variations of the same controls as user inputs. There are some differences in the way you populate each control.

Populating text input controls (<cfinput type="text">), textarea controls (<cftextarea>) and datefield controls (<cfinput type="datefield">) is straightforward if you simply use their bind property:

bind="{listingGrid.selectedItem.columnName}" 

Check box values can be true or false. The column that populates the checkbox control must be a Boolean type so that you can write:

value="{listingGrid.selectedItem.columnName}"

Select and radio button controls are a different challenge. Neither of them have a bind or similar attribute that you can use to bind them directly. Instead, you must make the controls acquire the right choice when the selected record in the datagrid changes.

In ActionScript, controls fire events when certain things happen. For example, the datagrid fires an onChange event each time the user selects an item. You can make your cfgrid call a function or run a piece of ActionScript code every time that event fires. To tell the datagrid what to do in that event, use the onChange attribute:

<cfgrid name="listingGrid" onchange="listingGridChanged()">

You can call any function you want, either a built-in function such as alert('Datagrid selection changed!') or a custom function.

If you choose to call a custom function, such as listingGridChanged(), you must declare it in a <cfformitem type="script"> block:

<cfformitem type="script">
public function listingGridChanged():Void {
    //select item in dropdowns
    //select item in radio button group
}	
</cfformitem>

To avoid repeating the same code for every select control, you can create a helper function to select a specific item in the select control. This function looks for the option value that matches the desired item and then selects it:

public function selectOption(select: mx.controls.ComboBox, optionToSelect:String):Void {
    
    //go through every record to find the right one
    for (var i:Number = 0; i< select.length; i++) {
        if (select.getItemAt([i]).data == optionToSelect){
            select.selectedIndex = i;
            break;
        }
    }
}

Lastly, to select a specific value in a radio button group, use the selectedData property:

myRadioButton.selectedData = listingGrid.selectedItem.columnName;

Putting everything together, the complete listingGridChanged() function looks like the following:

function listingGridChanged():Void {
    // select the matching state
    selectOption(edit_state, listingGrid.selectedItem.state);

// select the matching property type
    selectOption(edit_type, listingGrid.selectedItem.type);
    
    //select the matching choice in the radio button 
//for status
    edit_status.selectedData = listingGrid.selectedItem.status;
    
    //after selecting a radio button, it acquires focus, so bring focus back to grid
    listingGrid.setFocus();
}

Now the edit panel is correctly populated with the data in the selected row and the user can edit it and submit it to the server.

Note that if you use listingGrid.selectedItem.columnName directly, and there is no item selected in the datagrid, your controls may show undefined as their value. To avoid that, use the if-else shorthand statement to check whether the user has selected an item in the datagrid. If the user has selected an item, show the value; otherwise, show an empty control. For example, the city text input looks like the following:

<cfinput type="text" name="edit_city"  bind="{(listingGrid.selectedItem!=undefined)?listingGrid.selectedItem.city:''}" label="city" />