Jump to content

Odd IE error


KevinM1

Recommended Posts

So, I'm currently expanding my JavaScript library.  Basically, it's a bunch of functions found elsewhere that I want in a centralized location.  I've gone the route of creating namespaces for each logical division of my library.  So, there's a global namespace, a DOM namespace, a form namespace, etc.  The specialized namespaces (DOM, form, etc) are children of the global namespace.

 

I'm currently trying my hand at some AJAX stuff.  Right now, I have one function designed to return to me a proper XMLHttpRequest object or ActiveXObject depending on the browser.  As always, it works in Firefox, but not IE7.  So, here's the relevant part of my library (apologies for the lack of indents...Notepad++ indents don't seem to copy over correctly):

/**
*This is my first attempt at building a JavaScript library.
*While most of my code will use a pre-existing library (YUI, Scriptaculous, JQuery, Prototype, or Moo.fx), 
*I still have other helper functions I'd like to use.
*
*Date: May 19, 2008
*/

/**
*Global namespace
*/

var MP = {};

//-----------------------------------------------------------------------------------------------

MP.ajax =
{
/**
 *Function that equalizes XMLHttpRequest objects.
 *
 *Arguments:
 *None
 *
 *Return value:
 *@xmlHttp - either a new XMLHttpRequest object (if IE7, Mozilla, Safari, or Opera),  a new ActiveXObject (if IE's < 7), or null (if none of the above).
 *
 *Original Code:
 *From "Building Responsive Web Applications: AJAX and PHP" by Christian Darie et al.
 */

createXmlHttpRequestObject : function()
{
	var xmlHttp;

	try
	{
		//try the easy way first
		xmlHttp = new XMLHttpRequest();
	}
	catch(e)
	{
		//try the hard way next (IE6 or older)
		var XmlVersions = new Array('MSXML2.XMLHTTP.6.0',
											 'MSXML2.XMLHTTP.5.0',
											 'MSXML2.XMLHTTP.4.0',
											 'MSXML2.XMLHTTP.3.0',
											 'MSXML2.XMLHTTP',
											 'Microsoft.XMLHTTP');

		//try every version until we get one that works
		for(var i = 0; i < xmlVersions.length && !xmlHttp; i++)
		{
			try
			{
				xmlHttp = new ActiveXObject(xmlVersions[i]);
			}
			catch(e)
			{
				xmlHttp = null;
			}
		}
	}

	//return object (if we have one) or null
	return xmlHttp;
}
};

 

Here's my test code to see if it works:

<html>
<head>
   <title>XMLHttpRequest Test</title>
   <script type="text/javascript" src="js/MPlib.js"></script>
   <script type="text/javascript">
      window.onload = function()
      {
         var xmlHttp = MP.ajax.createXmlHttpRequestObject();

         if(xmlHttp)
         {
            alert("XMLHttpRequest object is type: " + xmlHttp.constructor);
         }
         else
         {
            alert("Cannot obtain XMLHttpRequestObject");
         }
      }
   </script>
</head>

<body>
</body>

</html>

 

IE keeps telling me that MP is undefined at the spot where I attempt to run the function.  It's not, as it works perfectly in Firefox, and I get no errors in Firefox's error console nor in Firebug.  IE still claims it's undefined even when I try to pre-assign it like so:

var MPNamespace = MP;
var xmlHttp = MPNamespace.ajax.createXmlHttpRequestObject();

 

Any ideas on how to make IE recognize my global namespace?

Link to comment
Share on other sites

Um, is there a reason you don't just use one of the many JS libraries already in existence? Why reinvent the wheel? A nice lite-weight one I use a lot is jQuery

 

Because I'm learning the nuts and bolts of both JavaScript and AJAX at the moment, and would like to get a clear idea of what's really going on behind the scenes (or, in AJAX's case, how a simple asynchronous exchange is structured and handled) before abstracting it all away behind a 3rd party library?  Like I said in my library's comments, I'll use a 'real'/professional library when doing 'real'/professional things (I've had my eye on YUI for a while, in part because its syntax is normal).  Right now I'm at the learning stage.  I figure any errors/bugs/issues I encounter now will give me valuable experience in dealing with them (or similar ones) when I move on.

 

In any event, I do appreciate your suggestion, but it doesn't help me at the moment.  I'd really like to know why IE is choking on my function invocation so I can possibly avoid that problem in the future.

Link to comment
Share on other sites

just because youre using a framework doesn't mean you are understanding javascript less. I use mootools or prototype. it makes cross browser ajax a lot easier and gives cleaner code so you can focus on the thing that really matters which is using javascript to make something work

Link to comment
Share on other sites

just because youre using a framework doesn't mean you are understanding javascript less. I use mootools or prototype. it makes cross browser ajax a lot easier and gives cleaner code so you can focus on the thing that really matters which is using javascript to make something work

 

I know, but I'd still like to figure out why IE is giving me problems with this seemingly obvious assignment.  I'm certain it's a Microsoft hiccup, as Firebug reports it as clean.  It's bugging me.

Link to comment
Share on other sites

First, is there anything else in  your MPlib.js?  If yes, please post the whole file.

 

Second, IE seems to think the object is undefined.  In your onload, try placing:

  alert(MP);
  alert(MP.ajax);
  alert(MP.ajax.createXmlHttpRequestObject);

 

You should get something like [Object object] for each of them.  If you don't, which one fails to return that string in the message box?

 

If alert(MP) doesn't say it's an object, then there's a good chance IE may not be loading MBlib.js at all, or you have a syntax error that FF is overlooking and IE is not.

Link to comment
Share on other sites

I loaded all your code, and while it says undefined, I am pretty sure IE is creating the object. It's just the constructor value is not getting set properly. In jQuery, they use this line of code to create the object:

var xmlHttp = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();

also, here is a w3schools site with some code:

http://www.w3schools.com/Ajax/ajax_browsers.asp

Link to comment
Share on other sites

First, is there anything else in your MPlib.js? If yes, please post the whole file.

 

Second, IE seems to think the object is undefined. In your onload, try placing:

 alert(MP);
 alert(MP.ajax);
 alert(MP.ajax.createXmlHttpRequestObject);

 

You should get something like [Object object] for each of them. If you don't, which one fails to return that string in the message box?

 

If alert(MP) doesn't say it's an object, then there's a good chance IE may not be loading MBlib.js at all, or you have a syntax error that FF is overlooking and IE is not.

 

Well, none of the alerts you suggested fired. I was thinking that it was a typo as well, but Firebug doesn't catch anything either.

 

Here's my entire library. Once again, apologies for the indent issues. Notepad++ hates message boards, apparently:

/**
*This is my first attempt at building a JavaScript library.
*While most of my code will use a pre-existing library (YUI, Scriptaculous, JQuery, Prototype, or Moo.fx), 
*I still have other helper functions I'd like to use.
*
*Date: May 19, 2008
*/

/**
*Global namespace
*/

var MP = {};

//-----------------------------------------------------------------------------------------------

/**
*DOM namespace
*/

MP.DOM =
{
/**
 *Function to get/set element attributes.
 *It normalizes those tricky cases of 'for' = 'htmlFor' and 'class' = 'className'.
 *
 *Arguments:
 *@elem - element we're accessing.
 *@name - name of the style.
 *@value - value of what we're setting (if any).
 *
 *Return value:
 *@object (CSS style)  - the style of @elem[@name].
 *
 *Original code:
 *From "Pro JavaScript Techniques" by John Resig.
 */

handleAttr : function(elem, name, value)
{
	//Make sure a valid name was provided
	if(!name || name.constructor != String)
	{
		return '';
	}

	//Figure out if the name was one of the weird naming cases
	name = {'for' : 'htmlFor', 'class' : 'className'}[name] || name;

	//If the user is setting a value, also
	if(typeof value != 'undefined')
	{
		elem[name] = value

		//If we can use setAttribute	
		if(elem.setAttribute)
		{
			elem.setAttribute(name, value);
		}
	}

	//Return the value of the attribute
	return elem[name] || elem.getAttribute(name) || '';
},

//-----------------------------------------------------------------------------------------------

/**
 *Function to create a new DOM element.
 *It normalizes XHTML and HTML element creation.
 *
 *Arguments:
 *@elem - type of element we're creating.
 *
 *Return value:
 *@object (DOM element) - DOM element of type @elem.
 *
 *Original code:
 *From "Pro JavaScript Techniques" by John Resig.
 */

createElem : function(elem)
{
	return document.createElementNS ? document.createElementNS('http://www.w3.org/1999/xhtml', elem) : document.createElement(elem);
}
};

//-----------------------------------------------------------------------------------------------

/**
*Form namespace
*/

MP.Form = {};

//-----------------------------------------------------------------------------------------------

/**
*Form handling/validation namespace.
*/

MP.Form.Validate =
{
/**
 *Function to see if a required input has had information entered into it.
 *
 *Arguments:
 *@elem - element we're checking.
 *
 *Return value:
 *@boolean - whether or not a required field value has been entered.
 *
 *Original code:
 *From "Pro JavaScript Techniques" by John Resig.
 */

 checkRequired : function(elem)
 {
	if(elem.type == "checkbox" || elem.type == "radio")
	{
		return getInputsByName(elem.name).numChecked;
	}
	else
	{
		return elem.value.length > 0 && elem.value != defaultValue;
	}
},

//-----------------------------------------------------------------------------------------------

/**
 *Helper function to find all input elements that have a specific name (good for those pesky checkboxes and radio buttons).
 *
 *Arguments:
 *@name - name of the elements we're looking for.
 *
 *Return value:
 *@results - an array of form inputs whose name matches @name.
 *
 *Original code :
 *From "Pro JavaScript Techniques" by John Resig.
 */

 getInputsByName : function(name)
 {
	//The array of input elements that will be matched.
	var results = [];

	//Counter to keep track of how many have been checked.
	results.numChecked = 0;

	//Find all input elements in the document.
	var inputs = document.getElementsByTagName("input");

	for(var i = 0; i < inputs.length; i++)
	{
		//Find all inputs that have the name we're looking for.
		if(inputs[i].name == name)
		{
			//Add it to the array
			results.push(input[i]);

			//Remember how many of the fields have been checked, if any
			if(input[i].checked)
			{
				results.numChecked++;
			}
		}
	}

	return results;
},

//-----------------------------------------------------------------------------------------------

/**
 *Function that validates an e-mail address.
 *This version accepts either an empty string or a properly-formed e-mail address.
 *If an e-mail address is required, either use the checkRequired() function, or modify this to not accept an empty string.
 *
 *Arguments:
 *@elem - the element whose value we're checking.
 *
 *Return value:
 *@boolean - whether or not the field value is valid.
 *
 *Original code:
 *From "Pro JavaScript Techniques" by John Resig.
 */

validateEmail : function(elem)
{
	return elem.value == '' || /^[a-z0-9_+.-]+\@([a-z0-9-]+\.)+[a-z0-9]{2,4}$/i.test(elem.value);
},

//-----------------------------------------------------------------------------------------------

/**
 *Function that validates an inputed URL.
 *This version accepts either an empty string, the default value (in this case, 'http://'), or a properly-formed URL.
 *If an URL is required, either use the checkRequired() function, or modify this to neither accept an empty string nor the default value.
 *
 *Arguments:
 *@elem - the element whose value we're checking.
 *
 *Return value:
 *@boolean - whether or not the field value is valid.
 *
 *Original code:
 *From "Pro JavaScript Techniques" by John Resig.
 */

validateURL : function(elem)
{
	return elem.value == '' || !elem.value == 'http://' || /^https?:\/\/([a-z0-9-]+\.)+[a-z0-9]{2,4}.*$/i.test(elem.value);
},

//-----------------------------------------------------------------------------------------------

/**
 *Other validation functions to be added later.
 */
};

MP.ajax =
{
/**
 *Function that equalizes XMLHttpRequest objects.
 *
 *Arguments:
 *None
 *
 *Return value:
 *@xmlHttp - either a new XMLHttpRequest object (if IE7, Mozilla, Safari, or Opera),  a new ActiveXObject (if IE's < 7), or null (if none of the above).
 *
 *Original Code:
 *From "Building Responsive Web Applications: AJAX and PHP" by Christian Darie et al.
 */

createXmlHttpRequestObject : function()
{
	var xmlHttp;

	try
	{
		//try the easy way first
		xmlHttp = new XMLHttpRequest();
	}
	catch(e)
	{
		//try the hard way next (IE6 or older)
		var XmlVersions = new Array('MSXML2.XMLHTTP.6.0',
											 'MSXML2.XMLHTTP.5.0',
											 'MSXML2.XMLHTTP.4.0',
											 'MSXML2.XMLHTTP.3.0',
											 'MSXML2.XMLHTTP',
											 'Microsoft.XMLHTTP');

		//try every version until we get one that works
		for(var i = 0; i < xmlVersions.length && !xmlHttp; i++)
		{
			try
			{
				xmlHttp = new ActiveXObject(xmlVersions[i]);
			}
			catch(e)
			{
				xmlHttp = null;
			}
		}
	}

	//return object (if we have one) or null
	return xmlHttp;
}
};

 

EDIT: Just for clarity's sake, those three alert functions aren't firing at all.  It's not a matter of 'undefined' popping up.  Nothing is popping up.

Link to comment
Share on other sites

ok...first, you have a variable wrong:

			var XmlVersions = new Array('MSXML2.XMLHTTP.6.0',

should be

			var xmlVersions = new Array('MSXML2.XMLHTTP.6.0',

 

Then, the constructor property doesn't have a value. Why, I couldn't tell you. But I just copied some code from w3schools to text the xmlHttp variable, and it works:

      window.onload = function()
      {
         var xmlHttp = MP.ajax.createXmlHttpRequestObject();
         xmlHttp.onreadystatechange = function ( )
         {
            if(xmlHttp.readyState==4)
            {
               alert(xmlHttp.responseText);
            }
         }
         xmlHttp.open("GET","test.php",true);
         xmlHttp.send(null);
      }

Link to comment
Share on other sites

ok...first, you have a variable wrong:

			var XmlVersions = new Array('MSXML2.XMLHTTP.6.0',

should be

			var xmlVersions = new Array('MSXML2.XMLHTTP.6.0',

 

Then, the constructor property doesn't have a value. Why, I couldn't tell you. But I just copied some code from w3schools to text the xmlHttp variable, and it works:

      window.onload = function()
      {
         var xmlHttp = MP.ajax.createXmlHttpRequestObject();
         xmlHttp.onreadystatechange = function ( )
         {
            if(xmlHttp.readyState==4)
            {
               alert(xmlHttp.responseText);
            }
         }
         xmlHttp.open("GET","test.php",true);
         xmlHttp.send(null);
      }

 

Thanks for finding the typo.  I'm amazed that it went through both IE and FF with it.  Neither have given me an error for the library file.

 

Are there any major differences between the various versions of the MSXML2.XMLHTTP ActiveX objects?  Because I'm tempted to just gut the other versions from the function (not that will help the non-construction of the MP object).

 

Oh, I tried some JQuery this afternoon.  I was hesitant at first, with the $("blah") syntax, but it seems simple enough.  Certainly easier to type than YUI's stuff.  Do you find more object-focused libraries (Prototype, for example) necessary?  I ask because JQuery seems good with the nitty-gritty aspects of JavaScript, but doesn't really have much beyond that.

Link to comment
Share on other sites

again, as I posted here, jQuery supports a WIDE range of browsers, and uses this to create the xmlHttp object:

var xmlHttp = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();

So, you should be safe with that.

 

I like jQuery cus it's small and fast. But I do use others like Script.aculo.us/Prototype, Dojo, Extjs for their widgets that they have.

Link to comment
Share on other sites

Sorry to bump this up, but I figure it's better to do that than to make another top-level thread.

 

Like I said before, I like working on the nuts-and-bolts of code because I feel it helps me understand what's going on.  I know it's not technically necessary, but I believe it helps me learn, so it's necessary to me.  I'm also a bit of a perfectionist, and like a good challenge.  So, on things like this, I tend to work on them even when I probably shouldn't.  Add my ego to the mix, and you get my first couple of snarky replies.  I sincerely apologize for those.

 

So, to get to the point, the good news is that I got my personal library code to work.  Turns out there was an extra comma in the MP.Form.Validate namespace/object, so that was messing up the whole thing.  I've also gotten the function to successfully create a XMLHttpResponse/ActiveXObject working.  So, in essence, I have the main building block in place.

 

I decided to test my new creation by having it work with the PHP script I used in conjunction with my JQuery AJAX tests (I'm loving JQuery, btw.  Still have to get used to some of the syntax, but it's great).  It works, but after receiving the response from the server, the system hangs.  It seems almost as though the connection isn't closing.  This happens regardless of whether or not I'm using the short, JQuery-esque, currently commented version of the createXmlHttpRequestObject() function or the long version, which is currently active.

 

Is there a way to manually close an XMLHttpRequest connection?  Or is something else going on?  I've put the relevant code below:

 

MPlib.js (only the important parts):

var MP = {};

//-----------------------------------------------------------------------------------------------

MP.Ajax =
{
/**
 *Function that equalizes XMLHttpRequest objects.
 *
 *Arguments:
 *None
 *
 *Return value:
 *@xmlHttp - either a new XMLHttpRequest object (if IE7, Mozilla, Safari, or Opera),  a new ActiveXObject (if IE's < 7), or null (if none of the above).
 *
 *Original Code:
 *From "Building Responsive Web Applications: AJAX and PHP" by Christian Darie et al.
 */

createXmlHttpRequestObject : function()
{
	/* var xmlHttp = (window.ActiveXObject) ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
	return xmlHttp; */

	var xmlHttp;

	try
	{
		//try the hard way because IE7 doesn't implement XMLHttpRequest() properly
		var xmlVersions = new Array('MSXML2.XMLHTTP.6.0',
											 'MSXML2.XMLHTTP.5.0',
											 'MSXML2.XMLHTTP.4.0',
											 'MSXML2.XMLHTTP.3.0',
											 'MSXML2.XMLHTTP',
											 'Microsoft.XMLHTTP');

		//iterate through the array until we get one that works
		for(var i = 0; i < xmlVersions.length && !xmlHttp; i++)
		{
			xmlHttp = new ActiveXObject(xmlVersions[i]);
		}
	}
	catch(e)
	{
		//try the easy way for the good browsers
		xmlHttp = new XMLHttpRequest();
	}

	//return object (if we have one) or null
	return xmlHttp;
}
};

 

ajaxtest.html:

<html>
<head>
   <title>XMLHttpRequest Test</title>
   <script type="text/javascript" src="js/MPlib.js"></script>
   <script type="text/javascript">
      window.onload = function()
      {
         alert(MP.constructor);
         alert(MP);
         alert(MP.Ajax);
         alert(MP.Ajax.createXmlHttpRequestObject);

         var xmlHttp = MP.Ajax.createXmlHttpRequestObject();

         if(xmlHttp)
         {
            alert("XMLHttpRequest object is type: " + xmlHttp.constructor);

            var param = encodeURIComponent("red");
            var paramStr = "action=" + param;

            xmlHttp.open("POST", "jqueryajax.php5", true);
            xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xmlHttp.onreadystatechange = handleRequest;
            xmlHttp.send(paramStr);
         }
         else
         {
            alert("Cannot obtain XMLHttpRequestObject");
         }

         function handleRequest()
         {
            if(xmlHttp.readyState == 4)
            {
               if(xmlHttp.status == 200)
               {
                  try
                  {
                     readResponse();
                  }
                  catch(e)
                  {
                     alert("Could not interact with the server");
                  }
               }
            }
         }

         function readResponse()
         {
            document.write(xmlHttp.responseText);
         }
      }
   </script>
</head>

<body>
</body>

</html>

 

jqueryajax.php5:

<?php
   if(isset($_POST['action']))
   {
      $action = $_POST['action'];

      if($action == 'red')
      {
         echo "<strong>This box is red</strong>";
      }
      else if($action == 'blue')
      {
         echo "<strong>This box is blue</strong>";
      }
   }
?>

 

Again, I'm going to use a professional library for legitimate projects.  This is just for my own learning.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.