Javascript Help: Prototype and AJAX

No Limit

Party Escort Bot
Joined
Sep 14, 2003
Messages
9,018
Reaction score
1
Today at work I played around with controlling some embedded electronics using Javascript and LabVIEW. I got everything working using regular javascript which was awesome. I got to monitor a 20,000 watt power supply using a web browser.

Here is the code:

PHP:
<html>
<head>
<script type="text/javascript">
var xmlhttp;
function loadXMLDoc()
{
xmlhttp=null;
var url="../LambdaWeb/Lambda/read_volts";
if (window.XMLHttpRequest)
  {// code for Firefox, Opera, IE7, etc.
  xmlhttp=new XMLHttpRequest();
  }
else if (window.ActiveXObject)
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
if (xmlhttp!=null)
  {
  xmlhttp.onreadystatechange=state_Change;
  xmlhttp.open("GET",url,true);
  xmlhttp.send(null);
  }
else
  {
  alert("Your browser does not support XMLHTTP.");
  }
}

function state_Change()
{
if (xmlhttp.readyState==4)
  {// 4 = "loaded"
  if (xmlhttp.status==200)
    {// 200 = "OK"
	var response_array = new Array();
	
	var response = xmlhttp.responseText;
	response_array = response.split('read_buffer');
	
	var foramted_volts = response_array[1];
	
	
    *************ElementById('T1').innerHTML=foramted_volts;
    }
  else
    {
	*************ElementById('T1').innerHTML=xmlhttp.statusText;
    }
  }
}
</script>
</head>

<body onload="loadXMLDoc(); setInterval('loadXMLDoc()', 1000 )" bgcolor="#000000">

<div id="T0">Volts:</div>
<div id="T1"></div>
<div ></div>
<div id="copyright">
<p>Sample TDK-Lambda Genesys Web 2.0 Program</p>
Program By: ****** @ *******</div>
</body>

</html>

But I'm having a hard time finding code examples of doing this with the prototype framework. All I would like to do is read a simple XML request and add it to an array in the javascript.

At this point the XML file looks something like this:

PHP:
<?xml version="1.0" encoding='UTF-8'?>
<data>
	<read_volts>
		10.001
	</read_volts>
	<read_current>
		2.874
	</read_current>
</data>

Anyone got any advice or code examples of how I can take XML data and assign it to a javascript array using prototype? I've been lookihng around and can't find any samples to work from. I would appreciate the help.
 
Does it have to be prototype? I'm fairly sure that's ridiculously simply with jQuery.
 
Hmmm..prototype seems ideal to me since that's what I've been learning as far as JS goes. But if jQuery is better I'll look in to this.

I did get JSON working with prototype yesterday, should have posted back here:

<html>
<head>
<META **********="Pragma" CONTENT="no-cache">
<META **********="Expires" CONTENT="-1">
<title>XML Test</title>
<script type="text/javascript" src="prototype.js"></script>
<script>
function ajax_request()
//Set up the AJAX Request Using Prototype Framework
{

new Ajax.Request("../LambdaWeb/lambda/read_volts", //URL
{
method:'get',
onSuccess : function(resp) {
//This function returns the JSON data from the server
//and assigns the data to the variable json
// To extract array use json.volts or json.current

var json = resp.responseText.evalJSON();

//Update the container for Volts
$('voltsContain').update(json.read_buffer);

//Update the container for Current
//$('currentDiv').update(json.current);
},
onFailure : function(resp) {
//This will return an alert if there is an error
//NOT A GOOD IDEA TO USE ALERT FUNCTION, JUST A SAMPLE
$('currentDiv').update("XML Data Error");
},
onLoading : function() {
//This will show the loading picture when a request is processing
$('loadingDiv').show();
},
onComplete : function() {
//This will hide the loading picture when a request is done
$('loadingDiv').hide();
$('loading_text').hide();
}
});

}
</script>
<STYLE type="text/css">
body {
background-color: #000;
font-family:Verdana, Geneva, sans-serif;
}
#voltsTitle {
height:80;
width:120;
padding:5;
color: #FFF;
font-size: 40px;
background-color:#000000; float: left;
}
#voltsContain {
border:1px solid white;
height:80;
width:200;
padding:5;
color: #060;
font-size: 40px;
background-color:#999999;
float: left;
text-align: center;
}
#Copyright {
color: #FFF;
font-size: 10px;
}
#Copyright p {
font-weight: bold;
}
.clearing {
clear: both;
}
#loadingDiv {
width:10px; height: 10px;
float: left;
background-color: #FFFFFF;
background-image: url(load.gif);
}

</style>
</head>
<body onLoad="javascript:setInterval('ajax_request()',1000);">

<div id="loading_text" >Loading Data...</div>

<div id="voltsTitle">Volts:</div>
<div id="voltsContain"></div>
<div id="loadingDiv" style="">
<p></p>
</div>
<div ></div>
<div id="copyright">
<p>Sample Lambda Web 2.0 Program</p>
Program By: ******* @ *******</div>


</body>
</html>

The problem is that the server I am using is LabVIEW and the license we have in house is LabVIEW 8.6 which only supports XML. LabVIEW 2009 which I have a beta off supports JSON and thats what I have running above, problem is a LabVIEW 2009 license will set us back around $10K. So it might be more cost effective for me to learn jQuery instead.
 
I've been reading about jQuery. This is what I have so far but for some reason it doesn't work:

PHP:
<html>
<head>
	<META **********="Pragma" CONTENT="no-cache">
	<META **********="Expires" CONTENT="-1">
	<title>jQuery/XML Test</title>
	<script type="text/javascript" src="js/jquery.js"></script>
	<script>
	$(document).ready(function(){
		$.get("../LambdaWeb/lambda/read_volts", function(data){
			alert("Data Loaded: " + data);
		});
	});
	</script>
</head>
<body>
</body>
</html>

I don't get any errors but the data it returns is empty. The XML data from the script looks like this:

Code:
<Response>
<Terminal>
  <Name>read_buffer</Name> 
  <Value>13.510</Value> 
</Terminal>
</Response>
 
You might have to add "xml" as the last parameter to your get() call... after the callback function.
 
Same thing:

PHP:
<html>
<head>
	<META **********="Pragma" CONTENT="no-cache">
	<META **********="Expires" CONTENT="-1">
	<title>jQuery/XML Test</title>
	<script type="text/javascript" src="js/jquery.js"></script>
	<script>
	$(document).ready(function(){
		$.get("../LambdaWeb/lambda/read_volts", function(data){
			alert("Data Loaded: " + data);
		}, "xml");
	});
	</script>
</head>
<body>
</body>
</html>

I tried doing text also and that didn't return anything. So I'm assuming its not pulling anything from the server but I know the XML data is there for sure.

I also attached a screenshot of the alert box, not sure if thats worth anything. Thanks for your help.
 

Attachments

  • screen_jQuery.gif
    screen_jQuery.gif
    3.2 KB · Views: 275
You might need to pass "null" for the 2nd parameter, which passes optional data to the GET request. This works for me:

HTML page:
PHP:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
$(function() {
	console.debug('loading...');
	$.get('xml.xml', null, function(data) { console.debug('loaded.'); $('#target').text($(data).find('foo bar').attr('foobar')); }, 'xml');
});
</script>
<div id="target"></div>
</body>
</html>

XML doc (xml.xml):
PHP:
<?xml version="1.0"?>
<foo>
	<bar foobar="1" />
</foo>

The result of the above for me is the string "1" being inserted into the div.
 
Adding null worked perfectly, thanks a lot!

Edit: NVM, see below.
 
Shit, actually it's because I had it set to "text" and not "xml". When I add XML it returns blank data again.

This works:

PHP:
<html>
<head>
	<META **********="Pragma" CONTENT="no-cache">
	<META **********="Expires" CONTENT="-1">
	<title>jQuery/XML Test</title>
	<script type="text/javascript" src="js/jquery.js"></script>
	<script>
	$(document).ready(function(){
		$.get("../LambdaWeb/lambda/read_volts", "", function(data){
			alert("Data Loaded: " + data);
		}, "text");
	});
	</script>
</head>
<body>
</body>
</html>

this doesn't:

PHP:
<html>
<head>
	<META **********="Pragma" CONTENT="no-cache">
	<META **********="Expires" CONTENT="-1">
	<title>jQuery/XML Test</title>
	<script type="text/javascript" src="js/jquery.js"></script>
	<script>
	$(document).ready(function(){
		$.get("../LambdaWeb/lambda/read_volts", "", function(data){
			alert("Data Loaded: " + data);
		}, "xml");
	});
	</script>
</head>
<body>
</body>
</html>
 
I wonder if maybe your service is returning invalid xml... for example, your snippet that you posted doesn't include the <?xml ?> declaration. I wonder if it's missing that if it can't be read as XML.

You said that it worked when you used the text mode, so maybe just read it as text... if you do that, can you traverse the document like I did in the sample I posted? If not, perhaps try adding the XML declaration yourself like this?:

PHP:
$.get('urlgoeshere', null, function(data) { var xml = $('<?xml version="1.0" ?>' + data); /* do whatever else here */ }, 'text');

EDIT: Now that I think about it, this was probably the problem with what you were doing with prototype. If you're more familiar with prototype, I'd expect you'd be able to do something similar where you load text and convert it to XML.

EDIT 2: What I posted should definitely work in jQuery... I was able to do this in the FireBug console:

Code:
$('<?xml version="1.0"><foo><bar foobar="1"/></foo>')

...and also:

Code:
$('<?xml version="1.0"><foo><bar foobar="1"/></foo>').find('foo bar').attr('foobar');
The above of course returns "1".
 
When I did that I now get [object] [object] returned so I think it works. That is weird, this is the raw data LabVIEW sends back:

Code:
HTTP/1.1 200 OK

Date: Tue, 18 Aug 2009 13:55:03 GMT

Server: Mbedthis-Appweb/2.3.0

Cache-Control: no-cache

Content-type: text/xml

Content-length: 87

Connection: keep-alive

Keep-Alive: timeout=60000, max=98



<Response><Terminal><Name>read_buffer</Name><Value>13.509</Value></Terminal></Response>

So it doesn't add the <xml> tag. Thanks for our help.
 
Ok, looks like we will be getting a LabVIEW 2009 license so I got access to JSON and will be using prototype. I started my script today and ran in to an issue with global variables. I would like to set a global variable 'ps_id' which will define which power supply we are reading at the time.

I found that I can set global variables fine outside of functions in prototype. But once doing it in prototype they don't seem to set (such as the onSuccess function under ajax.request).

So for example:

PHP:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta **********="Content-Type" content="text/html; charset=utf-8" />
    <title>Lambda Power Supply Control</title>
    <script type="text/javascript" src="prototype.js"></script>
    <script>
		
		var ps_id; //Current ID Of Power Supply
		
		document.observe('dom:loaded', function() 
			// This is triggered as soon as the DOM loads									
			{
				$('alarm').hide(); //Hide alarm since no alarm conidtion exists yet
				ps_list();
				alert(ps_id);
			}
		);
	
    	function ps_list() {
		  new Ajax.Request("../LambdaWeb/ps_list", //URL
		  { 
			   method:'get',
			   onSuccess : function(resp) { 
				  //This function returns the JSON data from the server
				  
				 var ps_array_raw = resp.responseText.evalJSON(); //This is raw JSON data
				 	ps_array = ps_array_raw.ps_list_array;
					ps_id = ps_array[0][0];
					
	 				ps_array.each(function(ps_info) 
					//This loops through the JSON array sent from the server
					//All info for each iteration is stored in the ps_info[] array.
					{  						
						$('PS_List_Contain').insert
						(
						 	"[url=\"#\"]" +ps_info[1] +"[/url]"
						 );
						
						$('PS_List_Contain').insert("[br]");
					}); 
			   }, 
			   onFailure : function(resp) { 
					alarm("FAILED");
			   },
			   onLoading : function() {

			   },
			   onComplete : function() {

			   }
		  });		
		  
		}
		function alarm(alarm_text) {
			$('alarm').show();
			$('alarm').update(alarm_text);
		}
    </script>
    <link href="css/style.css"  type="text/css" />
</head>

<body>
	<div id="alarm"></div>
	<div id="PS_List_Contain">
    
    </div>
</body>
</html>

ps_id remains undefined even after ps_list() has executed.

This is what the JSON data looks like, not sure if its needed:

Code:
{"ps_list_array":[["1","Test PS 1","TCPIP::10.1.1.8::INSTR","This is a test power supply."],["2","Test PS 2","TCPIP::10.1.1.8::INSTR","This is a test power supply 2."],["3","Test PS 2","TCPIP::10.1.1.8::INSTR","This is a test power supply 2."]]}

I would appreciate any help, thanks in advance.
 
I'll look at this in the morning, but if you use firebug, you can sprinkle calls to console.debug throughout to see what the values are. You can put as many arguments as you want in the method call and they'll all render separately in the console and be clickable if they're objects. If you aren't using firebug, give yourself a good slap in the face for making your work harder than it should be and then go install firebug.
 
Shoot, I don't use firefox. So I slapped myself in the face, opened up firefox, and installed it. Awesome tool! I was able to set some break points and it turns out that the variable is getting set globally after the function completes. But it seems the alert pops up before this variable is set. Is that's how its supposed to work? The alarm function doesn't wait for the ps_list() function to finish?
 
AH! Yes. Ajax.Request would be an asynchronous call (it is, after all, the "A" in Ajax, no?), which means that it fires off the request and continues on to do other things.

Your onSuccess (or any other) callback would only be firing after the browser receives a response from that Ajax call. So even if that's only something like 5-15ms from a local device, it's still longer than it takes for it to execute the next couple lines of code. To be clear, it wasn't that alert() wasn't waiting for ps_list() to finish... ps_list() DID indeed finish, and then the alert() call was executed.

So, you'd need to put your alert() call in the callback itself.
 
Ahh, that makes perfect sense. This entire application is coming along really nice now, thanks again for all your help.
 
Back
Top