Home / AJAX

HOW TO Create an Editable View with Two-Way Data Binding

RSS
Modified on 2009/12/16 22:39 by Erik Reitan Categorized as Uncategorized
This topic describes how to use both one-way and two-way live data binding in an ASP.NET AJAX template. Live data binding updates the UI of a DataView control to reflect changes in the data. The types of data binding that are available in ASP.NET AJAX include the following:

Inline expression evaluation. Inline binding expressions do not update the rendered value when data changes.
  • One-way binding.
  • Two-way binding.
  • One-time binding.

For more information about these binding types, see DataView Control and Ajax Templates.

To illustrate one-way data binding, this topic uses an example of a Web page that includes ASP.NET AJAX DataView client controls. One control retrieves data from a Web service and displays a list of items (the master view). When an item in the master view is selected, the item is displayed by using another DataView control that also enables users to edit it (the detail view). Because the example page uses live binding, changes that the user makes to the data are automatically reflected in the UI.

Adding One-Way Live Binding to a Master-View Template

Live one-way binding keeps data values updated in the UI when the underlying data item is changed. Live one-way binding syntax uses single braces and the binding keyword, as in the following example:
<span>{binding CompanyName}</span>

To add one-way live binding to a master-view template

  1. Using HTML markup, create a block element that supports child elements and give the element an id attribute.
  2. Set the class attribute of the element to sys-template.
    Note: 
    
    The CSS sys-template class should be styled as display:none, so that the uninstantiated template is not visible on the page.
  3. Specify the following attributes to configure the element as a DataView template:
    • sys:attach. Specify "dataview" to instantiate a DataView control that is attached to this HTML element. The contents of the element will be used as the item template by the DataView control.
    • dataview:autofetch. Set to true to enable data to be retrieved immediately after the page is loaded.
    • dataview:sys-key. Specify a name for the DataView control that you can use to refer to this control.
    • dataview:dataprovider. Specify the URI of the Web service that is called to get the data.
    • dataview:fetchoperation. Specify the method of the Web service that is invoked to get the data.
  4. Optionally, include a dataview:selecteditemclass attribute and specify the CSS class to apply to individual data items.
  5. Inside the block element, create a single child element that defines how individual data items will be displayed. In the child element, specify the following:
    • sys:command="select". This makes the item selectable in the DataView control, by raising the Select command when the user clicks the item.
    • A one-way binding to a field of the data item to display, using the following syntax:
      { binding fieldName }

      The following example shows how to create markup for a master-view template that implements one-way binding. The master-view template is created as an HTML table. The tbody element is configured as a template for the DataView control. Individual data items are defined as tr elements, and expressions inside td elements bind to fields of the data item.

      <table id="companyListView">
      <thead>
      <tr>
      <td>Company Name</td>
      <td>Contact</td>
      <td>URL</td>
      <td>Income</td>
      <td>Expenses</td>
      </tr>
      </thead>
      <tbody class="sys-template"
      sys:attach="dataview"
      dataview:autofetch="true"
      dataview:sys-key="master"
      dataview:dataprovider="CompanyService.svc"
      dataview:fetchoperation="GetCompanies"
      dataview:selecteditemclass="myselected">
      <tr sys:command="select">
      <td>{binding CompanyName }</td>
      <td>{binding Contact }</td>
      <td>{binding Url }</td>
      <td>{binding Income, convert=formatCurrency }</td>
      <td>{binding Expenses, convert=formatCurrency }</td>
      </tr>
      </tbody>
      </table>


Adding Two-Way Live Binding to a Detail-View Template

As with one-way binding, two-way binding updates the data value that is rendered by the template if the underlying data changes. In addition, two-way binding lets users change the data value through the UI. These changes are then reflected in the corresponding property value of the underlying data item.

You designate two-way binding by using the single-brace binding syntax to bind to the value of an HTML input element, as in the following example:
<input 
 type="text" 
 id="detailsCompanyName" 
 value="{binding CompanyName}" />

To add two-way live binding to a detail-view template

  1. Create a block element and set the following attributes:
    • sys:attach. Specify "dataview" to indicate that the element is a template for the DataView control.
    • dataview:data. Specify a data-binding expression that indicates that the details-list template is bound to the selectedData property of the master-view DataView control.
  2. Inside the block element, create a child element for each field of the data item that you want to display. For data that the user can edit, use an input element.
  3. In the child element, use two-way live binding syntax to specify the binding to the chosen data item field.
    The following example shows how to configure a div element that contains a child fieldset element as a detail-view template. The input and legend elements specify live binding.
       
    <div class="sys-template"
    sys:attach="dataview"
    dataview:autofetch="true"
    dataview:data="{binding selectedData, source={{ master }} }">
    <fieldset>
    <legend>{binding CompanyName}</legend>
    <label for="detailsName">Company Name:</label>
    <input type="text" id="detailsCompanyName"
    sys:value="{binding CompanyName}" /><br />
    <label for="detailsContact">Contact:</label>
    <input type="text" id="detailsContact" sys:value="{binding Contact}" /><br />
    <label for="detailsUrl">URL:</label>
    <input type="text" id="detailsUrl" sys:value="{binding Url}" /><br />
    <label for="detailsIncome">Income:</label>
    <input type="text" id="detailsIncome"
    sys:value="{binding Income, convert=formatCurrency,
    convertBack=parseCurrency}" /><br />
    <label for="detailsExpenses">Expenses:</label>
    <input type="text" id="detailsExpenses"
    sys:value="{binding Expenses, convert=formatCurrency,
    convertBack=parseCurrency}" /><br />
    </fieldset>
    </div>

    In the example, the binding expressions for the Income and Expenses fields include a convert and convertBack property, which specify a JavaScript functions (formatCurrency and parseCurrency). These are used to convert the data value to an appropriate string format for display in the view (a currency), and to convert the user input string back into the appropriate data format (a floating point value).

Example

The following example shows a complete HTML file that implements a master-detail scenario that uses one-way and two-way live binding. For information about the Web service that is referenced as the data source in this example, see Walkthrough: Using a DataView with Local Data.
      
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Editable Master Detail</title>
  <script type="text/javascript" 
      src="MicrosoftAjax.js"></script>
  <script type="text/javascript" 
      src="MicrosoftAjaxTemplates.js"></script>
  <script type="text/javascript">
      function formatCurrency(value) {
          return value.localeFormat("C");
      }

function parseCurrency(value) { if (value.substr(0, 1) == '$') { value = value.substr(1) } return Number.parseLocale(value); } </script>

<style type="text/css"> .sys-template { display: none; visibility: hidden; } .myselected { color: white; font-weight: bold; background-color: Silver; } </style> </head> <body xmlns:sys="javascript:Sys" xmlns:dataview="javascript:Sys.UI.DataView">

<h1>Company List</h1> <div id="top"> <table id="companyListView"> <thead> <tr> <td>Company Name</td> <td>Contact</td> <td>URL</td> <td>Income</td> <td>Expenses</td> </tr> </thead> <tbody class="sys-template" sys:attach="dataview" dataview:autofetch="true" dataview:sys-key="master" dataview:dataprovider="CompanyService.svc" dataview:fetchoperation="GetCompanies" dataview:selecteditemclass="myselected"> <tr sys:command="select"> <td>{binding CompanyName }</td> <td>{binding Contact }</td> <td>{binding Url }</td> <td>{binding Income, convert=formatCurrency }</td> <td>{binding Expenses, convert=formatCurrency }</td> </tr> </tbody> </table> </div>

<div class="sys-template" sys:attach="dataview" dataview:autofetch="true" dataview:data="{binding selectedData, source={{ master }} }"> <fieldset> <legend>{binding CompanyName}</legend> <label for="detailsName">Company Name:</label> <input type="text" id="detailsCompanyName" sys:value="{binding CompanyName}" /> <br /> <label for="detailsContact">Contact:</label> <input type="text" id="detailsContact" sys:value="{binding Contact}" /> <br /> <label for="detailsUrl">URL:</label> <input type="text" id="detailsUrl" sys:value="{binding Url}" /><br /> <label for="detailsIncome">Income:</label> <input type="text" id="detailsIncome" sys:value="{binding Income, convert=formatCurrency, convertBack=parseCurrency}" /><br /> <label for="detailsExpenses">Expenses:</label> <input type="text" id="detailsExpenses" sys:value="{binding Expenses, convert=formatCurrency, convertBack=parseCurrency}" /><br /> </fieldset> </div> </body> </html>