View Full Version : Function "breaking" when going to server...

Dec 29th, 2006, 02:16 PM
This is more of an advanced question... So sorry in advance for the long post, but I want to try explaining this as best I can so I can get better feedback (and to maybe teach more novice JS coders along the way)

I'm working on an in-house, inventory web-application that uses a menu-driven system. I have created a myMenu object that has several different properties including a menuHeading that is the clickable <div> that gets displayed as the menu-item. I use this code to create the menuHeading:

function myMenu(uidNumber, nextsib, childMenu, prevsib, parentMn, isViewed)
// Object Variables
this.menuName = "Menu"+uidNumber;
this.nextSibling = (arguments[1])?nextsib:0;
this.firstChild = (arguments[2])?childMenu:0;
this.prevSibling = (arguments[3])?prevsib:0;
this.parentMenu = (arguments[4])?parentMn:0;
this.menuHeading = null;
// Other stuff using isViewed

// ---------

myMenu.prototype.makeHeader=function(headerText, tooltip)
// Create the heading <div>
var newDiv = document.createElement('div');

// Add header text
newDiv.appendChild(haltSymbol()); //Adds a red \u2612 character to text

// Add attributes to element
newDiv.className='heading close';
if (tooltip!="") newDiv.title=tooltip;
newDiv.setAttribute("prog", "halt");

// Add to myMenu object

The problem I'm having is with the onclick function (which I've commented out in the code above). A "vanilla" version of this program works fine with the "toggle(this)", which calls a toggle function supplying the menuHeading <div> as the argument (ie "this" refers to the menuHeading <div>). I call it "vanilla" because the program control stays with the current page after toggle()'ing the menu-item and, say, entering in a serial number on the main page.

The more robust version calls a callToServer() function after the user enters in the serial-number, which is an early version of AJAX in that it opens a hidden iframe, has that call up a .php page on the server (where the S/N gets stored in a MySQL DB), and calls a response function back on the main page. This whole process seems to work fine until the user tries clicking on a new menu-item. Then I get a "toggle() is not defined" error and it points to the function-assignment line in the above code.

Curiously, the DOM in a debugging Firefox plugin shows that "this" after the error still refers to the menuHeading object. In fact, I can call "alert(this.id);" in place of toggle() (see the other commented line) and it displays the menuHeading's id correctly (also, using the alert() instead of the toggle() causes no error even in the robust version). Because "this" is being assigned correctly (as far as I'm able to determine), I'm thinking it is not a problem with the menuHeading prototype's closure around "this", but rather is truly about the program not being able to find toggle.

One last thing I notice about this problem... In the AJAX-like php file, I call the response function using "parent.showNext()" because the iframe's parent is the document that contains the showNext function. The php, after doing the DB work, essentially opens a tiny HTML page with a <head> that has "window.onload = function () { parent.showNext() }". Is it possible that after returning control to the response function, the program still thinks it's in the iframe and so needs to refer to the parent document?

Since the program knew what "this" was and knew other properties of "this" I was thinking that I might be able to make toggle() one of "this"'s functions. What I mean, although do not know how to implement it, would be to have toggle() be a prototype function for menuHeading so as to more closely assign the function with its object. Then the onclick would be "menuHeading.onclick = function() { this.toggle() }" and may get around the problem of the program not knowing where (ie in what scope) toggle is defined.

Can anyone think of any solutions? Or can anyone help me in making toggle a menuHeading prototype function?

I got it to work... Instead of using the AJAX-like callToServer() function which used an iframe, I used an actual AJAX call back to the server with a JSON-like response function which ran the echoed javascript via eval(). It'd still be interesting to find out why the first way was failing, however, just to learn how not to fall into that pit again.