Previous Page
Next Page

12.11. My-Tickets Component

The my-tickets component is the user's default screen within the application; it provides the user with a list of tickets that have been assigned to him or her. This component does a large amount of dynamic table processing and tries hard to load the minimal amount of data it needs from the server. The data minimization is important because when you're viewing your ticket list, it will poll the server on a 30-second interval, looking for updated tickets. You can see the my-tickets view in Figure 12-14, which is created from myTickets.php (see Listing 12-19).

Figure 12-14. The my-tickets view


Listing 12-19. MyTickets.php

1  <div id="myTickets" class="section">
2  <div style="font-size: 80%; visibility: hidden;"
3    id="mtLoading">Updating ...</div>
4  <table id="mtTable" cellspacing="0">
5  <thead>
6    <tr>
7      <th>#</th>
8      <th>Title</th>
9      <th>Status</th>
10     <th>Last Change</th>
11     <th>Opened By</th>
12   </tr>
13 </thead>
14 <tbody>
15   <tr id="mtTemplate">
16   <td><a href="javascript:viewTicket({$ticket_id});"
17     >{$ticket_id}</a></td>
18   <td>{$title}</td>
19   <td>{$status}</td>
20   <td>{$last_change}</td>
21   <td>{$creator}</td>
22   </tr>
23 </tbody>
24 </table>
25
26 </div>

This component has a small template but a large amount of functionality. The template contains two elements: a notice area to display a message when the table is being updated (lines 23) and the actual table that shows the user's assigned tickets. The table contains a header, which is contained in the thread tag so that the buildTable function won't remove it. It also contains a table in its body, which will be cleared when buildTable updates the table. The template is marked with an ID so that it can be pulled out during page load by the component's setup function. The tokens are in the format described in the explanation of the updateRow function, so the {$status} will be replaced with the corresponding status line from the server. This simple templating system gives a great deal of flexibility, which is shown on lines 1617, where we add a link around the ticket_id. The matching JavaScript that uses this HTML is shown in Listing 12-20.

Listing 12-20. myTickets.js

1  app.logout.push(function() {
2    var tbody = byId('mtTable').tBodies[0];
3    for(var i = tbody.rows.length-1; i >= 0; i--) {
4      tbody.deleteRow(i);
5    }
6    app.since = false;
7  });
8  app.setup.push(function() {
9
10 function mtOnDisplay() {
11   if (app.since) {
12     startUpdate();
13   }
14   else {
15     app.since = new Date();
16     rMt.listAssignedTickets();
17   }
18 }
19
20 function mtSetup() {
21   app.templates['mtTable'] =
22     byId('mtTemplate').cloneNode(true);
23   byId('mtTable').tBodies[0].removeChild(
24     byId('mtTemplate'));
25
26   byId('myTickets').onDisplay = mtOnDisplay;
27   window.setInterval(
28   function() {
29     if (byId('myTickets').style.display
30       == 'block') {
31       startUpdate();
32     }
33   },30000);
34
35 }
36 app.setup.push(mtSetup);
37
38 var mtCallback = {
39   listAssignedTickets: function(result) {
40     buildTable(result,'mtTable');
41   },
42   listUpdatedTickets: function(result) {
43     updateTable(result);
44   }
45 };
46 var rMt = new Ticket(mtCallback);
47
48 function startUpdate() {
49   var since = app.since;
50   app.since = new Date();
51
52   var current = [];
53
54   var rows = byId('mtTable').tBodies[0].rows;
55   for(var i = 0; i < rows.length; i++) {
56     current.push(rows[i].ticket_id);
57   }
58
59   byId('mtLoading').style.visibility = 'visible';
60   rMt.listUpdatedTickets(since.getTime(),current);
61 }
62
63 function updateTable(data) {
64   byId('mtLoading').style.visibility = 'hidden';
65   if (data['rebuild']) {
66     buildTable(data['tickets'],'mtTable');
67     return;
68   }
69   var tbody = byId('mtTable').tBodies[0];
70   for(var i = 0; i < data.length; i++) {
71     var row = app.mtTemplate.cloneNode(true);
72     updateRow(row,data[i]);
73
74     var replace = -1;
75     for(var r = 0; r < tbody.rows.length; r++) {
76       if (tbody.rows[r].ticket_id

77         == data[i].ticket_id) {
78         replace = r;
79         break;
80       }
81     }
82
83     if (replace == -1) {
84       tbody.insertBefore(row,tbody.rows[0]);
85     }
86     else {
87       tbody.removeChild(tbody.rows[replace]);
88       tbody.insertBefore(row,tbody.rows[0]);
89     }
90   }
91 }

MyTicket.js starts by creating three setup functions:

  • The first is a function to be called when the user logs out (lines 17). This function is needed to clear out the user's current tickets so that the tickets currently shown won't be reused if another user logs in from the same browser.

  • The second is the onDisplay function (1018), which runs when the page is displayed and sends an AJAX request to the server to update the list of tickets that are being shown.

  • The third is the Setup function (lines 2036), which runs on page load. This function clones the row template for the table, storing it in the app object (lines 2124). It registers the onDisplay function (line 26), and it sets up a function to run on a 30-second interval (lines 2333). This function will run every 30 seconds while this page is loaded. The function does a simple check to see if the user is on the My Tickets section (line 29); if it is, the function starts the update process (line 31).

Lines 3846 set up the AJAX class for this component. Callbacks are set up for the listAssignedTickets method, which is used on initial page load, and for listUpdatedTickets, which is used to get updates afterward. The Ticket instance is created on line 46.

The startUpdate function (lines 4861) gets the data needed to call the server's listUpdateTicket method. This method needs the last time an update was asked for, which is stored in app.since (lines 4950). It also needs a list of the current tickets being displayed, which is created by looping over the ticket table and reading the ticket_id property on each row (lines 5457). Once this data is ready, a loading indicator is shown (line 59) and the AJAX call is made (line 60).

Finishing up the component is the updateTable function (lines 6391). This function takes the data returned from the server and updates the ticket table with it. The function starts by disabling the loading indicator set by the startUpdate function (line 64); it then checks to see what type of data was returned. If it is a complete set of data (lines 6568), then the buildTable function is used, and the function stops. If there is an updated set of data, we loop over the new data, inserting new rows at the top of the table or replacing current ones. Lines 7071 prepare the new row, using updateRow and its template system. Lines 7481 determine if we are doing an update or a replace; this check is done by looping over the current tickets and looking for matching ticket_ids. If the ID exists, then we are updating a current row by removing the old row and inserting the new one (lines 8788). If the ID doesn't exist in the table, we insert a new row at the top of the table.


Previous Page
Next Page