Head Rush Ajax by Brett McLaughlin The unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification This page was updated July 11, 2007. UNCONFIRMED errors and comments from readers: {Multiple} Multiple; By default all newer version of PHP have register_globals turned off by default. I just started reading the book, but all PHP code should use either $_GET or $_POST to get the HTML form values passed. I am only up to chapter 2 but this problem appears in both lookupCustomer.php and placeOrder.php (the former needs $_GET and the latter needs the $_POST). Although this is not really a technical mistake, but an assumption of a php setting, most people who are not familiar with PHP will have problems with the samples because of this. There are other ways around this such as getting all the variables and making their scope global, changing the php.ini to enable register_globals,... but using the $_GET or $_POST is probably the most reliable and cleanest way to do it. {78} 1st box; You tell the "onChange"-event for text input elements is triggered whenever the content changes. This is not correct, as while typing in a sequence of 10 letters, the onChange-event is NOT triggered 10 times as the reader would think. In fact "onChange" should better be thought of as "onBlurAndChange", since the changyness is checked "on blur". [81] code error inside placeOrder.php supplied in downloaded example; insert a session start PHP before HTML tag: ?php session_start(); if (isset($_POST['address'])) $_SESSION['address'] = $_POST['address']; if (isset($_POST['order'])) $_SESSION['order'] = $_POST['order']; ?> further down the page replace these two PHP command: ", $address); ?> and: ", $order); ?> with these: ", $_SESSION['address']); ?> and: ", $_SESSION['order']); ?> Without opening these session variables, the script will break because the form variables haven't been transfered to the script: placeOrder.php [121] Graphic of the Break Neck Pizza page in a browser window.; The browser graphic has the form elements in the wrong order. It should show "Type your order in here:" before "Your order will be delivered to:". The text to the left of the graphic that explains the form elements are mixed up. "While the server is looking up the address, the customer types in the pizza order." points to the address textarea, it should point to the pizza order textarea. (143) The top graphic of the Break Neck Pizza browser window ; The top browser window graphic shows the Break Neck Pizza form with the elements in the wrong order. It should match the bottom browser window graphic. "Type your order in here:" should be before "Your order will be delivered to:". {149} Just Do It -- contents of coffee.css, downloaded; The css for the coffeeorder and coffeemaker2 divs does not render accurately in IE7 -- particularly, the coffeemaker2 block appears outside of and far right of the wrapper division. I found that changing the entries to match the following gave good results in both IE and Firefox: div#coffeeorder { position: relative; top: 20px; /* was 60px */ /* removed entry for left */ width: 100%; /* was 300px */ margin: 0; /* removed entry for padding */ } div#coffeemaker2 { position: absolute; top: 10px; right:10px; /* was margin-left:520px; */ padding: 10px; width: 200px; background-color: #f5f5f5; border:double medium black; float: right; } {153} Middle of page,
; I was unable to get the second coffee maker image to appear next to the coffee mug as it is listed in the pictures. I ended up moving the
from below the "controls1"
to above it and moving the

line below the second coffee maker image. I also added a
to the

Coffee Maker #1

Coffee Maker #1

Idle

Coffee Pot 1

Coffee Maker #2

Coffee Maker #2

Idle


Place your coffee order here:

. . . This solved the problem for me in Firefox on both Linux and Windows. But then, I don't know if it was just and issue *I* was having or if it was a problem for anyone else. {156} Here's what we did... Code by the ajax.js; var request = false; should be var request = null; (158) last div in the html sample; I am using IE version: 6.0.2900.2180.xpsp_sp2_grd.050301-1519. When using the unchanged coffee.css that I downloaded, the second coffee maker disappears as soon as the div is given the correct ID. To correct the problem I had to change the left margins as follows: div#coffeemaker2, margin-left: 320px (instead of 520px). div#coffeeorder, margin-left: 20px (instead of 220px). If I don't change the margins for both of these coffeeorder will overlap coffeemaker2, and coffeemaker2 will be off the page. Is this just an IE problem? (168) Comments to the code; replaceText() instead of reaplaceText() as in replaceText() takes an element, and the text to put... {173} screenshot of browser; When visiting the web site http://www.headfirstlabs.com/books/hrajax/chapter03/coffee/coffee.html The coffee maker #2 image does not display on the page in IE 7, but rather shows on the far right if you scroll over. It does display correctly in Firefox. {255} FAQ box, fourth question; The question "Isn't there an addEventHandler() method?" This should be addEventListener(), but it's still not supported in IE (and microsoft have blogged that it won't be in IE7 either :( - maybe IE8). [258] Top; In a discussion about javascript event handlers, the book states that "this" points to the element that caused the event. I have been unable to find any reference to a "this" pointer for event handlers in any javascript reference that I can find. I tried it, and in I.E. - "this" seems to be pointing to the document. The code I use to get the element that caused the event is: function getElement(evt) { evt = (evt) ? evt : event; if (evt.target) { node = evt.target; while(node.nodeType != node.ELEMENT_NODE) node = node.parentNode; return node; } if (evt.srcElement) return evt.srcElement; return evt; } Then I call getElement at the beginning of every event handler that wants to talk to the element that caused the event. (268) Comment to items 3-4-5; function instead of fiunction as in The rest of this all applies to your addToTop5() JavaScript function. (292, 294) code at bottom; I ran into a problem trying to run: header("Status: No order was received.", true, 400); I have two sites I use for hosting and when I tried to run this on the one site that runs php via suEXEC, it doesn't run and needs to be changed to: header("Status: 400 No order was received.", true); After I got that working, I also had to make a change on page 294 and change: var message = request.getResponseHeader("Status"); to var message = request.statusText; The code as it is in the book will work on servers running php as an Apache module, just not on servers running php via suEXEC. {294} 4th bolded line in showConfirmation function; "if ((message.length == null) || ..." should be "if ((message == null) || ..." {356} Chapter 6 -- getUpdatedSales.php; $bootsSold = 1672; $boardsSold = 312; $bindingsSold = 82; should be $boardsSold = 1672; $bootsSold = 312; $bindingsSold = 82; this makes the example work correctly {356} getUpdatedSales.php & displays on page 356 don't match; php file getUpdatedSales.php initial values for boards and boots are reversed: is: // Start with an arbitrary number of sales $bootsSold = 1672; $boardsSold = 312; $bindingsSold = 82; s/b: // Start with an arbitrary number of sales $bootsSold = 312; $boardsSold = 1672; $bindingsSold = 82; You may want to change the rand values to make the sales a little more dramatic: is: // Reflect new sales srand((double)microtime() * 1000000); $bootsSold = $bootsSold + rand(0,10); $boardsSold = $boardsSold + rand(0,5); $bindingsSold = $bindingsSold + rand(0,3); s/b: // Reflect new sales srand((double)microtime() * 1000000); $bootsSold = $bootsSold + rand(0,100); $boardsSold = $boardsSold + rand(0,1000); $bindingsSold = $bindingsSold + rand(0,100); (380-1) json examples; The JSON examples pp 380-381, if imported literally will not eval() [Firefox, for one] if the semi colon exists as the last character. It took me a while to figure that out. Once that was eliminated, smooth sailing. And so much better than xml, imo. (381) Gray code box, 3rd line; Though it is not used in the solving the problems on the page, there is a colon after isbn inside the quotations. I am assuming that the items in quotes have to be identical across the array. Thus it should be: ..., "isbn":"0679767800"}, not ..., "isbn:":"0679767800"}, [383] Downloaded code for Chap. 7; The error is in the downloaded code for Chapter 7. My download was as of 08-March-2007. The following line of code is missing from the top of the file 'getUpdatedSales.php' and should be inserted after line 1. require_once('JSON.php'); [392] Sending a request:; /***** Printed Data: ************* var request = new Ajax.Request( url, { method: 'get', parameters: 'phone=2142908762&name=Mary', onSuccess: updatePage, onFailure: reportError } *********************************/ Missing closing parentheses and semi-colon at the end of call. [404] text-utils.js function clear text; This function will NOT delete all child nodes as it should. The problem lies in the 'for loop' construction. 'for( i=0' and 'i++' mean that i starts at 0 and increments each time the loop iterates. 'i < el.childNodes.length' means that each time that the loop iterates it checks to see if i has exceeded the number of child nodes present. The problem is that el.childNodes.length is CHANGING as the loop runs. For example: I have a div with three children [0] [1] and [2]. first loop iteration: i=0 and the 0th node is removed leaving [1] and [2]. i increments to 1 test condition tests is i (1) < el.childNodes.length (2!) yes i=1 and [1] is removed i increments to 2 test condition tests is i (2) < el.childNodes.length (1!) NO!!! The loop terminates leaving [2] still attatched!!! Here is a solution: for (var i = el.childNodes.length-1; i >= 0 ; i--) { var childNode = el.childNodes[i]; el.removeChild(childNode); }