Detail View / Detail Lists

So far, we've implemented the interface for creating and modifying record in a single table. You can easily add new fields to the landlords table such as address, date of birth and so on. This doesn't change the structure of the application and therefore doesn't add to programming complexity.

Next we'll add a "Phone Numbers" section in the landlord view, so that a list of phone numbers can be maintained.

The first step is to design the database table. Since a landlord can have zero, one or many associated phone numbers, we'll be using a one-to-many relationship. This is accomplished by having the primary key of the main table as the foreign key in the sub table.

For example, the primary key of the landlords table is llid. We add the llid field to the landlordphonenumbers field:

lpid primary key, auto increment, unsigned integer
llid unsigned integer, indexed
phone varchar(255)

Note the table name follows the convension of main record's name plus sub record's name in plural form.

Now populate this table with some test data, so that at least three numbers are associated with a landlord that's already in the database.

Add a Phone Numbers section in the landlord view:

//showlandlord.php
function showlandlord($llid=null){
  // ...
?>
<div class="sectionheader">Phone Numbers</div>
<table>
<?
$query="select * from landlordphonenumbers
where llid=$llid order by lpid";
$rs=sql_query($query,$db);
while ($myrow=sql_fetch_array($rs)){
  $phone=$myrow['phone'];
?>
<tr><td><?echo $phone;?></td>
<td><a>[x]</a></td>
</tr>
<?
} // while
?>
<tr><td>
<input id="landlordphone_new_<?echo $llid;?>">
</td><td>
<button onclick="addlandlordphone(<?echo $llid;?>);">
  Add Phone
</button>
</td></tr>
</table>
<?
  // ...
}

Reload the page and you should see the 3 phone numbers that are added to the database are displayed in the landlord view. This should provide you a basis to visualize the rest of the functionality.

What do you think should happen when the user enters a number in the input field and click on the "Add Phone" button? Well, a new row of the added number should show up in addition to the existing 3 numbers. And when the [x] button is clicked on, the phone number should be removed from the list. Now without writing any code, think about how the above two interactions, namely insertion and deletion, could be implemented.

The button should invoke a JavaScript function that gathers the new number. The phone number is then handled by a server-side function that adds the number to the database. Upon completion, the new list of numbers should be displayed in the landlord view.

Read the last sentence again. Also read showlandlord.inc.php again.

You must realize that the current implementation of showlandlord has two issues. First of all, there is nowhere to inject the server response. Second, the phone number insertion function has no display function to piggy back to.

The first issue can be resolved by adding a container:

<div class="sectionheader">Phone Numbers</div>
  <div id="landlordphonenumbers_<?echo $llid;?>">
    ...
  </div>

Take a look at what we did in updatelandlord server handler. We called an independent showlandlord function. Similar we could factor out the code for displaying phone numbers and store it in a separate file.

Create a file listlandlordphonenumbers.inc.php in the icl folder.

<?php
function listlandlordphonenumbers($llid){
  global $db;
  $query="select * from landlordphonenumbers
  where llid=$llid order by lpid";

  $rs=sql_query($query,$db);

  while ($myrow=sql_fetch_array($rs)){
    $phone=$myrow['phone'];
  ?>
  <tr><td><?echo $phone;?></td>
  <td><a>[x]</a></td>
  </tr>
  <?
  } // while
  ?>
  <tr><td>
  <input id="landlordphone_new_<?echo $llid;?>">
  </td><td>
  <button onclick="addlandlordphone(<?echo $llid;?>);">
    Add Phone
  </button>
  </td></tr>
  </table>
  <?
}

The list container still stays in showlandlord.inc.php:

<?php
include 'icl/listlandlordphonenumbers.inc.php';
function showlandlord($llid=null){
  // ...
?>
<div class="sectionheader">Phone Numbers</div>
  <div id="landlordphonenumbers_<?echo $llid;?>">
    <? listlandlordphonenumbers($llid); ?>
  </div>
<?
  // ...
}

The steps to follow are straightforward. We add a client-side handler in landlords.js:

addlandlordphone=function(llid){
  var phone=gid('landlordphone_new_'+llid).value;
  phone=encodeHTML(phone);
  ajxpgn('landlordphonenumbers_'+llid,
    document.codepage.appsettings+
    '?cmd=addlandlordphone&llid='+llid+
    '&phone='+phone);
}

In myservices.php, add a clause to the switch:

case 'addlandlordphone':
  include 'icl/addlandlordphone.inc.php';
  addlandlordphone();
break;

Implement the insertion function in addlandlordphone.inc.php:

<?php
include 'icl/listlandlordphonenumbers.inc.php';
function addlandlordphone(){
  $llid=GETVAL('llid');
  $phone=GETVAR('phone');

  global $db;
  $query="insert into landlordphonenumbers (llid,phone)
    values($llid, '$phone')";

  sql_query($query,$db);
  listlandlordphonenumbers($llid);
}
At this point you should see a pattern. The content is first displayed in a tab, or any kind of DIV container. The content contains components such as input fields that collect data from the user. A trigger such as a button or link invokes a JavaScript function that assembles the user input and sends it to a server-side switch. The switch clause further includes and calls the serverside handler. If the handler modifies the data, it also includes the displaying function and piggyback the updated result that's injected back to the original container. This flow is the bread and butter of building web applications; it is used extensively in Gyroscope.

Let's review this process again by adding deletion of phone numbers from the list.

First, we add the "trigger" for deleting a record.

In listlandlordphonenumbers, add an event to the [x] button:

while ($myrow=sql_fetch_array($rs)){
  $lpid=$myrow['lpid'];
  $phone=$myrow['phone'];
  ?>
  <tr><td><?echo $phone;?></td><td>
  <a onclick="dellandlordphone(<?echo $lpid;?>,<?echo $llid;?>);">
    [x]
  </a>
  <?
  </td></tr>
}//while

Note that we're passing both IDs to the JavaScript handler. The first ID, lpid, uniquely identifies a landlord-phone pair in the database. It is all we need to delete a record. The landlord ID is needed both for calling the display function as well as targeting the container.

In landlords.js, we add the deletion handler:

dellandlordphone=function(lpid,llid){
  if (!confirm('Are you sure?')) return;
  ajxpgn('landlordphonenumbers_'+llid, document.appsettings.codepage+
    '?cmd=dellandlordphone&lpid='+lpid+'&llid='+llid);
}

Add a clause to the switch in myservices.php:

case 'dellandlordphone':
  include 'icl/dellandlordphone.inc.php';
  dellandlordphone();
break;

Create the server-side handler dellandlordphone.inc.php:

<?php
include 'icl/listlandlordphonenumbers.inc.php';

function dellandlordphone(){
  $lpid=GETVAL('lpid');
  $llid=GETVAL('llid');
  global $db;
  $query="delete from landlordphonenumbers where
    lpid=$lpid and llid=$llid";
  sql_query($query,$db);

  listlandlordphonenumbers($llid);
}
Again, lpid is enough to uniquely locate and delete the record. The reason llid is added to the where-clause is because it could catch logic programming errors. It's a good sanity check to have.

Table of Content

Our Services

Targeted Crawlers

Crawlers for content extraction, restoration and competitive intelligence gathering.

Learn More

Gyroscope™ ERP Solutions

Fully integrated enterprise solutions for rapid and steady growth.

Learn More

E-Commerce

Self-updating websites with product catalog and payment processing.

Learn More