Shop OBEX P1 Docs P2 Docs Learn Events
Using AJAX to Update a Web Page in Real Time — Parallax Forums

Using AJAX to Update a Web Page in Real Time

Mike GMike G Posts: 2,702
edited 2012-11-20 07:36 in Accessories
I’m receiving more and more PMs and emails asking the same basic question. How do I display the state of my devices on a single web page in real time? I prefer AJAX to do this sort of thing.

Before jumping into AJAX, we need to dabble in client server architecture for a moment.

In the Internet world, there are servers and clients. Clients request server resources and server fulfill requests with a response. A browser running on a PC is an example of a client. It is important to understand that once a server sends a response to a client, the transaction is over. The client is only connected to the server during the request/response transaction. Once the transaction is complete, the client is no longer connected to the server and the server is free to serve up resources to the next client.

Back to the original question, how do I see my stuff in real time?

AJAX Asynchronous JavaScript And XML.

Client side JavaScript requests XML resources from a server, the server responds, the client extracts the data, then writes the data to specific tags on the loaded HTML page. This all happens behind the scene and without requesting an entire web page.

Below is an example of an XML document. It has a root element named <root> and child elements. The child elements contain values.
<?xml version="1.0" encoding="utf-8"?>
<root>
	<text>Hello world</text>
	<number>1234</number>
	<pi>3.1415</pi>
	<date>1/1/1753</date>
</root>

The objective of this exercise is to place the element values of <text>, <number>, <pi>, and <date> in an HTML page loaded in the browser.

Attached are two files, xmlexample.htm and data.xml, the web page and xml document respectively. Download and unzip the example to a folder on your PC. Open the file xmlexample.htm in a browser and click the Get Data link. The page will update and display the 4 XML element values above.


AJAX Code explanation:

Instantiate the XMLHttpRequest (req) used to create client requests. This code runs the first time the page loads; var req = getXmlHttpRequestObject();.
function getXmlHttpRequestObject() {
	 if (window.XMLHttpRequest) {
		 return new XMLHttpRequest();
	 } else if (window.ActiveXObject) {
		 return new ActiveXObject("Microsoft.XMLHTTP");
	 } else {
		 alert("Your Browser does not support AJAX!\nIt's about time to upgrade don't you think?");
	 }
 }
 
//XmlHttpRequest object
 var req = getXmlHttpRequestObject(); 


Create an HTTP GET request and assign a handler. The handler is invoked when the HTTP requests returns from the server - Asynchronous.
function getRequest(resource) {
 	
	// handle the case where a querystring is not detected
	var char = "&";
 	if(resource.indexOf("?", 0) == -1) {
		char = "?";
	}
		
	 if (req.readyState == 4 || req.readyState == 0) {
		 req.open("GET", resource + char + 'ms=' + new Date().getTime(), true);
		 req.onreadystatechange = handleResponse;
		 req.send(null);
		 return false;
	 }
 }

The handler receives the XML document and directs execution to parseState. parseState is responsible for placing the element values in the HTML page; xmlexample.htm.

document.getElementById("text") gets a reference to the HTML tag to update.

xDoc.getElementsByTagName("text")[0].childNodes[0].nodeValue gets the xml element value
	function handleResponse() {
		 if (req.readyState == 4) 
		 {
			parseState(req.responseXML);
		 }
	} 

	function parseState(xDoc){
		if(xDoc == null)
			return
			
		//Reference the <div> tag with the ID "text"; <div id="text">XML</div>	
		var target = document.getElementById("text");
		//Get the value of the xml node named <text> and place the value in <div id="text">here</div>
		target.innerHTML = xDoc.getElementsByTagName("text")[0].childNodes[0].nodeValue;
		
		target = document.getElementById("number");
		target.innerHTML = xDoc.getElementsByTagName("number")[0].childNodes[0].nodeValue;
		
		target = document.getElementById("pi");
		target.innerHTML = xDoc.getElementsByTagName("pi")[0].childNodes[0].nodeValue;
		
		target = document.getElementById("date");
		target.innerHTML = xDoc.getElementsByTagName("date")[0].childNodes[0].nodeValue;
	}

Below are the HTML tags to update. Notice the ID attributes have the same name as the XML elements. This is not necessary. I did this so the example is easy to read.

Clicking the link invokes the HTTP get
<body>
    <h1>XML Example</h1>
    <div id="text">null</div>
    <div id="number">nothing</div>
    <div id="pi">nada</div>
    <div id="date">blank</div>
    <a href="#" onclick="getRequest('data.xml'); return false;">Get Data</a>
</body>

Lastly, use the Javascript setInterval method to setup a timer to request the XML. This timer will create a client request every second.
setInterval(getRequest('data.xml'), 1000)

A Spinneret is not required to the run this example. All you need is a web browser. So have fun and hack away.

More information:
http://www.w3schools.com/xml/xml_http.asp
«1

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-09-19 09:25
    Mike,

    Thanks for that and for all your server/client tips and Spinneret code! Without your contributions, I doubt that the Spinneret would be nearly as viable a product as you've helped to make it.

    -Phil
  • Igor_RastIgor_Rast Posts: 357
    edited 2012-09-19 15:42
    I agree with Phill . nice piece Mike
  • Mike GMike G Posts: 2,702
    edited 2012-09-19 19:19
    Thanks guys
  • RforbesRforbes Posts: 281
    edited 2012-11-10 05:54
    Argh...

    Ok- I've followed this example, but something still isn't making sense for me. I'm not sure where to go from here.

    I'm trying to automatically update my"Live.htm" file whenever I click the "get data" link. The data comes from a long Tank_Level which could be a value from 0 to 186.

    Live.htm
    <!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 http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Parse XML</title>
    <script language="javascript" type="application/javascript">
    
     function getXmlHttpRequestObject() {
         if (window.XMLHttpRequest) {
             return new XMLHttpRequest();
         } else if (window.ActiveXObject) {
             return new ActiveXObject("Microsoft.XMLHTTP");
         } else {
             alert("Your Browser does not support AJAX!\nIt's about time to upgrade don't you think?");
         }
     }
     
    //XmlHttpRequest object
     var req = getXmlHttpRequestObject();
    
     function getRequest(resource) {
         
        // handle the case where a querystring is not detected
        var char = "&";
         if(resource.indexOf("?", 0) == -1) {
            char = "?";
        }
            
         if (req.readyState == 4 || req.readyState == 0) {
             req.open("GET", resource + char + 'ms=' + new Date().getTime(), true);
             req.onreadystatechange = handleResponse;
             req.send(null);
             return false;
         }
     }
    
        function handleResponse() {
             if (req.readyState == 4) 
             {
                parseState(req.responseXML);
             }
        } 
    
        function parseState(xDoc){
            if(xDoc == null)
                return
                
            //Reference the <div> tag with the ID "Live"; <div id="Live">XML</div>    
            var target = document.getElementById("Live");
            //Get the value of the xml node named <Live> and place the value in <div id="Live">here</div>
            target.innerHTML = xDoc.getElementsByTagName("Live")[0].childNodes[0].nodeValue;
    
                }
    
    </script>
    </head>
    
    <body>
        <h1>Live data XML Example</h1>
        <div id="Live">----</div>
    
        <a href="#" onclick="getRequest('Livedata.xml'); return false;">Get Data</a>
    </body>
    </html>
    
    

    Livedata.xml
    <?xml version="1.0" encoding="utf-8"?>
    <root>
        <Live>Here's my live data</Live>
    
    </root>
    

    Dispatcher Method
    PRI Dispatcher(id)
    '' HTTP request handler
       
      ' The RESTful command is in the root location
      if(strcomp(Request.GetPathNode(id, 0), string("led")))
        RestLed(id)
        return
    
      ' XML time
      if(strcomp(Request.GetPathNode(id, 0), string("xmltime")))
        XmlTime(id)
        return
    
      if(strcomp(Request.GetPathNode(id, 0), string("pagecnt")))
        PageCount(id)
        return
    
      if(strcomp(Request.GetPathNode(id, 0), string("getsntp")))
        'GetSntp(3)
        XmlTime(id)
        return
    
        '' Live Data
        if(strcomp(Request.GetPathNode(id, 0), string("Live.htm")))
            Live(id)
            return
        
      ' Send requested file content
      StaticFileHandler(id)
      return
    
    

    And Live method
    PRI Live(id)|headerOffset
    {{
      If the request header has "Live" in it, we do stuff in this method.
      The variable "Tank_Level" contains the value 0-186. It can change 10 times per second.
      But, we only want to update it on the web page once every 10 or 15 seconds, or on a mouse click.
    }}
      dynamicContentPtr := @tempBuff
      PushDynamicContent(@xmlencode)
      PushDynamicContent(string("<root application='multisocket'><Live.htm'"))      
      PushDynamicContent(Tank_Level)
      PushDynamicContent(string("'><![CDATA["))
      PushDynamicContent(string("]]></Live></root>"))
    
        '' Write the header and XML body
      headerOffset := Response.BuildHeader(string("xml"), 200, false)
      Socket.txTCP(id, @txdata, headerOffset)
      StringSend(id, @tempBuff)
        
      bytefill(@tempBuff, 0, TEMP_BUFFER)
      return
    
    

    If I drop both the files on the SD card, it works as expected... when I enter the IP, Port and File name it shows up with "----" and then when I click the "Get Data" link, the text "Here's my live data" shows up.
    I'm not getting how to go about making it show the value of my Tank_Level variable.. Help? Heeeelllllllllppp?! :smile:
  • Mike GMike G Posts: 2,702
    edited 2012-11-10 06:18
    Livedata.xml is requested but a Livedata.xml filter does not exist in the dispatcher. I'd drop the extension too since the response is dynamic.


    Update the HTML/JavaScript
    <a href="#" onclick="getRequest('Livedata'); return false;">Get Data</a>
    

    Add the filter
    '' Live Data
        if(strcomp(Request.GetPathNode(id, 0), string("Livedata")))
            Live(id)
            return
    
  • Mike GMike G Posts: 2,702
    edited 2012-11-10 06:40
    Secondly, Tank_Level must be a string pointer not an integer. HTTP is text based.
     str.ToString(@Tank_Level, @numBuff) 
     PushDynamicContent(@numBuff)
    
  • RforbesRforbes Posts: 281
    edited 2012-11-10 07:07
    Ok, I've updated my Live.htm per your instructions, and made the other changes as well.

    When I enter "http://172.16.150.242:5000/Live.htm&quot; in my browser, I get the Live.htm page to render, but the "get data" link does nothing.

    When I enter "http://172.16.150.242:5000/Live&quot; instead, I get the following error:
    XML Parsing Error: not well-formed
    Location: http://172.16.150.242:5000/Live
    Line Number 1, Column 80:<?xml version='1.0' encoding='utf-8'?><root application='multisocket'><Live.htm'186'><![CDATA[]]></Live></root>
    ^

    My new Dispatcher and Live methods are:
    PRI Dispatcher(id)
    '' HTTP request handler
    
      '' Live Data
      if(strcomp(Request.GetPathNode(id, 0), string("Live")))
         Live(id)
         return
    
      ''Live Data
      if(strcomp(Request.GetPathNode(id, 0), string("Livedata")))
         Live(id)
         return
    
        
      ' Send requested file content
      StaticFileHandler(id)
      return
    
    PRI Live(id)|headerOffset
    {{
      If the request header has "Live" in it, we do stuff in this method.
      The variable "Tank_Level" contains the value 0-186. It can change 10 times per second.
      But, we only want to update it on the web page once every 10 or 15 seconds, or on a mouse click.
    }}
      dynamicContentPtr := @tempBuff
      PushDynamicContent(@xmlencode)
      PushDynamicContent(string("<root application='multisocket'><Live.htm'"))      
      str.ToString(@Tank_Level, @numBuff) 
      PushDynamicContent(@numBuff)
      PushDynamicContent(string("'><![CDATA["))
      PushDynamicContent(string("]]></Live></root>"))
    
        '' Write the header and XML body
      headerOffset := Response.BuildHeader(string("xml"), 200, false)
      Socket.txTCP(id, @txdata, headerOffset)
      StringSend(id, @tempBuff)
        
      bytefill(@tempBuff, 0, TEMP_BUFFER)
      return
    
    
  • Mike GMike G Posts: 2,702
    edited 2012-11-10 07:22
    The XML response XML is malformed.
    PRI Live(id)|headerOffset
    {{
      If the request header has "Live" in it, we do stuff in this method.
      The variable "Tank_Level" contains the value 0-186. It can change 10 times per second.
      But, we only want to update it on the web page once every 10 or 15 seconds, or on a mouse click.
    }}
      dynamicContentPtr := @tempBuff
      PushDynamicContent(@xmlencode)
      PushDynamicContent(string("<root application='multisocket'><Live.htm><![CDATA["))
      str.ToString(@Tank_Level, @numBuff) 
      PushDynamicContent(@numBuff)
      PushDynamicContent(string("]]></Live></root>"))
    
        '' Write the header and XML body
      headerOffset := Response.BuildHeader(string("xml"), 200, false)
      Socket.txTCP(id, @txdata, headerOffset)
      StringSend(id, @tempBuff)
        
      bytefill(@tempBuff, 0, TEMP_BUFFER)
      return
    

    The XML should look like
    <?xml version='1.0' encoding='utf-8'?>
      <root application='multisocket'>
        <Live.htm><![CDATA[186]]>
      </Live>
    </root>
    

    You can remove [CDATA[]] if you want. CDATA allows the XML to contain special characters.
  • RforbesRforbes Posts: 281
    edited 2012-11-10 08:52
    Mike,

    Success!!!

    I had a couple type-O's in there and got them straightened out. With your input and the type-o's gone, it's working. I'm going to work on the setInterval method for auto updates next but I need to get some family time in for the afternoon. Thanks again!

    Robert
  • RforbesRforbes Posts: 281
    edited 2012-11-12 13:01
    Ok, I've gotten the setInterval method worked out, and I'm now happily updating my web page every second without user intervention.

    I have realized I don't need an xml file on the SD card, since the Dispatcher method is building the xml header and body on the fly. I just have to have the htm file on the card. But for some reason, Firefox displays everything perfectly and IE8 (I'm running windows XP here) doesn't update the values. Is this a common issue? I'm not getting any errors in IE8 or anywhere else that I know of. It just doesn't... well, doesn't update the data on the screen.
  • Mike GMike G Posts: 2,702
    edited 2012-11-12 16:14
    IE has a aggressive caching scheme. Make sure you are using the AJAX example posted. The example adds the current time in ms to the URL querystring which forces IE to retrieve the request from the server.

    [php]
    function getRequest(resource) {

    // handle the case where a querystring is not detected
    var char = "&";
    if(resource.indexOf("?", 0) == -1) {
    char = "?";
    }

    if (req.readyState == 4 || req.readyState == 0) {
    req.open("GET", resource + char + 'ms=' + new Date().getTime(), true);
    req.onreadystatechange = handleResponse;
    req.send(null);
    return false;
    }
    }
    [/php]
  • JavalinJavalin Posts: 892
    edited 2012-11-15 03:48
    Mike,

    Firstly - ditto PhilPi's comment - thanks for the work you put into this. Its a great plaform.

    Secondly.... A question. I've downloaded the htm & xml file, and trying to run them locally using IE9 (32bit) on Win7 x64, but nothing happens when I press Get Data. Javascript is installed and working. Browser defaults to IE9 mode. Any ideas? IE Security change needed?

    Thanks,
    James
  • Mike GMike G Posts: 2,702
    edited 2012-11-15 11:37
    I get Access Denied! So it looks like a security issue. I'm not sure how to solve it without creating a more complex example.
  • JavalinJavalin Posts: 892
    edited 2012-11-15 12:13
    Hiya

    This code works if you put it on a webserver, spineret or IIS.

    I've got this far from editing the w3schools example, and trying to fuse it with the html5 graph code in other thread.
    <!DOCTYPE html>
    <html>
    <head>
    <title>Javalins WebSite</title>
    
    <script type="text/javascript" src="graph.js"></script>
    
    <script>
    
    function GetXML(rsXMLPage)
    {
      if (window.XMLHttpRequest)
      {// code for IE7+, Firefox, Chrome, Opera, Safari
          xmlhttp=new XMLHttpRequest();
      }
      else
      {// code for IE6, IE5
          xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
      }
      xmlhttp.open("GET",rsXMLPage,false);
      xmlhttp.send();
      xmlDoc=xmlhttp.responseXML;
     
      document.getElementById("data").innerHTML=xmlDoc.getElementsByTagName("data")[0].childNodes[0].nodeValue;
    
      alert('Hello -> ' + xmlDoc.getElementsByTagName("data")[0].childNodes[0].nodeValue);
    
      g_graph_1 = new Graph(
      {
            'id': "firstgraph",
            'strokeStyle': "#1100FF",		// line colour
            'fillStyle': "rgba(11,0,254,0.25)",	// fill colour
        	'showdots': true,   			// Show data points as dots
        	'showgrid': true,   			// Show the grid
        	'showlabels': true, 			// Show labels for each data point
    	'grid': [4,10],     			// X,Y cell width's
    	'range': [0,105], 			// XY range
            'data': [1,2,3]
      });
    }
    </script>
    
    </head>
    
    <body onload="GetXML('data.xml');">
     <h1>W3Schools Internal Note</h1>
    
    <div>
     <b>Data:</b> <span id="data"></span>
    </div>
    
    <table>
    <tr><th align="center" style="font-family:arial;color:Blue;font-size:20px;">Temperature</th></tr>
    <tr><td><canvas id="firstgraph" width="1000" height="200"></canvas></td></tr>
    <tr><th align="center" style="font-family:arial;color:#1100FF;font-size:10px;">(Celcius)</th></tr>
    </table>
     
    </body>
     </html>
    

    All I am stuck with now is how to get the xmlDoc.getElementsByTagName("data")[0].childNodes[0].nodeValue; to return the value into the 'data': [1,2,3] graph bit.

    my data.xml looks like:
    <?xml version="1.0" encoding="utf-8"?>
    <root>
        <data>1,2,3,4,5,6,7,8,9,10</data>
    </root>
    

    Any ideas?

    James
  • Mike GMike G Posts: 2,702
    edited 2012-11-15 15:18
    This code works if you put it on a webserver, spineret or IIS.
    That's what I getting at. I'd have to explain how to drop the files on a web server. Not really feeling up to it. Glad you got it working.

    The data node contains a string. I'm guess you want an array? What are you trying to do?
    <data>1,2,3,4,5,6,7,8,9,10</data>
    
    It is possible to create an array from the comma separated values. First the string must be split by the comma; data.split(","). The individual array elements (numbers) must be converted to integers using intParse().

    This foramt allows you to enumerate the XML in JavaScript
    <?xml version="1.0" encoding="utf-8"?>
    <root>
      <myArray>
        <element id="0">0</element>
        <element id="1">1</element>
        <element id="2">2</element>
        <element id="3">3</element>
        <element id="4">4</element>
        <element id="5">5</element>
      </myArray>
    </root>
    

    or this
    <?xml version="1.0" encoding="utf-8"?>
    <root>
      <item1>
        <value>0</value>
      </item1>
      <item2>
        <value>1</value> 
      </item2>
    </root>
    
  • Igor_RastIgor_Rast Posts: 357
    edited 2012-11-15 15:37
    @James
    Thougth I jump in , I must have forgotten to put the js files also in the html5graph tread . anyway
    the javascript and spin code that takes the values and puts them in the correspondending nodes inside the xml looks like below


    first this code is what,s keeps calling the request to keep getting the data live
    setInterval("getRequest('xmltemp', 'placeholder')", 1000);
    

    this calls the js below

    [HTML]//XmlHttpRequest object
    var req = getXmlHttpRequestObject();
    var htmlTarget;
    var timer = 0;

    function getRequest(resource, elementId) {

    // handle the case where a querystring is not detected
    var char = "&";
    if(resource.indexOf("?", 0) == -1) {
    char = "?";
    }

    if (req.readyState == 4 || req.readyState == 0) {
    req.open("GET", resource + char + 'ms=' + new Date().getTime(), true);
    req.onreadystatechange = handleResponse;
    htmlTarget = elementId;
    req.send(null);
    return false;
    }
    }

    function handleResponse() {

    if (req.readyState == 4) {
    timer = 0;
    parseState(req.responseXML);
    }
    /*
    if(req.readState == 1 || req.readyState == 3){
    timer++;
    }

    if(timer == 2000)
    parseState(null);
    */
    }

    function parseState(xDoc) {
    if(xDoc == null)
    return

    var target = document.getElementById("placeholder");
    target.innerHTML = xDoc.getElementsByTagName("temp")[0].childNodes[0].nodeValue;

    var target = document.getElementById("placeholder2");
    target.innerHTML = xDoc.getElementsByTagName("humidity")[0].childNodes[0].nodeValue;

    var target = document.getElementById("tmax");
    target.innerHTML = xDoc.getElementsByTagName("tmax")[0].childNodes[0].nodeValue;

    var target = document.getElementById("tmin");
    target.innerHTML = xDoc.getElementsByTagName("tmin")[0].childNodes[0].nodeValue;

    var target = document.getElementById("lvmax");
    target.innerHTML = xDoc.getElementsByTagName("lvmax")[0].childNodes[0].nodeValue;

    var target = document.getElementById("lvmin");
    target.innerHTML = xDoc.getElementsByTagName("lvmin")[0].childNodes[0].nodeValue;

    var target = document.getElementById("setpoint_1");
    target.innerHTML = xDoc.getElementsByTagName("setpoint_1")[0].childNodes[0].nodeValue;

    var target = document.getElementById("offset_1");
    target.innerHTML = xDoc.getElementsByTagName("offset_1")[0].childNodes[0].nodeValue;

    var target = document.getElementById("function_1");
    target.innerHTML = xDoc.getElementsByTagName("function_1")[0].childNodes[0].nodeValue;


    }[/HTML]

    letting the xml look like below
    [HTML]<root>
    <temp>24.0</temp>
    <humidity>43</humidity>
    <tmax>26.6</tmax>
    <tmin>19.7</tmin>
    <lvmax>51</lvmax>
    <lvmin>32</lvmin>
    <setpoint_1>00</setpoint_1>
    <offset_1>00</offset_1>
    <function_1>00</function_1>
    </root>[/HTML]

    At the prop side . ,. There is this below taking place
    1 . in the DAT section there is the XMl placeholders .
    [HTML] xml byte "HTTP/1.1 200 OK", CR, LF, {
    } "Content-Type: text/xml", CR, LF, CR, LF, {
    } "<?xml version='1.0' encoding='utf-8'?><root><temp>"
    temperature byte $30, $30, $2E, $30, "</temp><humidity>"
    lvlv byte $30, $30, "</humidity><tmax>"
    t_max byte $30, $30, $2E, $30, "</tmax><tmin>"
    t_min byte $30, $30, $2E, $30, "</tmin><lvmax>"
    lv_max byte $30, $30, "</lvmax><lvmin>"
    lv_min byte $30, $30, "</lvmin><setpoint_1>"
    set_p byte $30, $30, "</setpoint_1><offset_1>"
    off_s byte $30, $30, "</offset_1><function_1>"
    fun_1 byte $30, $30, "</function_1></root>", 0[/HTML]

    in the multisocket, where the parseresourese gets the xml call . it does the following
    PUB ParseResource | value
    
      if(req.UrlContains(string("xmltemp"))) 
            Settemp(tempc3,@temperature)
            Setlv(lv3,@lvlv)
            Settemp(tempmax,@t_max)
            Settemp(tempmin,@t_min)
            Setlv(lvmax,@lv_max)
            Setlv(lvmin,@lv_min)
            Setlv(setpoint_1,@Set_p)
            Setlv(offset_1,@off_s)   
            Setlv(function_1,@fun_1)                   
            return @xml
    

    PUB Settemp ( value,buffer) | t1
    
      t1 := value
      t1 := t1/100
      value -= t1 * 100
      byte[buffer][0] := t1 + $30
    
      t1 := value
      t1 := t1/10
      value -= t1 * 10
      byte[buffer][1] := t1 + $30
      
      t1 := value
      byte[buffer][3] := t1 + $30
      
      
    PUB SetLV(value,buffer) | tx1                                              
      tx1 := value
      tx1 := tx1/10
      value -= tx1 * 10
      byte[buffer][0] := tx1 + $30
      
      tx1 := value
      byte[buffer][1] := tx1 + $30
    

    wich gets the data from the rom/ram and gets it placed inside the right placeholders ,. after that they get sent out .

    hopefully you can follow it to modify it to your needs.
  • JavalinJavalin Posts: 892
    edited 2012-11-16 01:28
    Thanks Mike and Igor,

    Yes I want to use an array, based on a comma seperated string. I'll knock up some more Javascript then.

    Will let you know,

    James
  • JavalinJavalin Posts: 892
    edited 2012-11-16 05:43
    OK - so partially solved, need to tweak the graph.js library when I am home (need to edit the code on the webserver), but:
    function james1()
    {
        var i = 0;
        var newArray=new Array();
        var DataString = "1,5,10,15,20,19,18,17,16,15,14,13,12,11,10";
        var SplitData = DataString.split(",");
    
        for(i=0;i<SplitData.length-1;i++)
        {
    	newArray[i] = SplitData[i];
        }
    
        alert ('is : ' + SplitData[0] + ' and ' + newArray[4]);
        // alert('done');
    
        g_graph_1 = new Graph(
        {
            'id': "firstgraph",                     // graph
            'strokeStyle': "#1100FF",		// line colour
            'fillStyle': "rgba(11,0,254,0.25)",	// fill colour
        	'showdots': true,   			// Show data points as dots
        	'showgrid': true,   			// Show the grid
        	'showlabels': true, 			// Show labels for each data point
    	'grid': [10,10],     			// X,Y cell width's      
    	'range': [0,100]
        });
        g_graph_1.data = newArray;
    }
    

    Is messy, but takes a comma delimited string (which will come from 'data.xml') and pass it to the graph using the:
    g_graph_1.data = newArray;
    

    Just need to modify the default behaviours in the graph.js library so it doesn't start doing its 'call' method.

    Update later.

    James
  • Igor_RastIgor_Rast Posts: 357
    edited 2012-11-16 06:46
    Ok , ill read up later again , . cant realy understand the hole picture there , loooking forward for an example when its working

    @ Mike , I was trying to get a placeholder to display a text based on the value of a second placeholder(
    the xml loads the function_1 placeholder . with a value ranging from 1 to 4 depending on this settting.

    This number , I want to convert to the name of the funtion , But cant realy get it workin g,
    I was tring with a javaschript to get the values , but this is not working ,and I am deffinitly not good with javascript
    function setting_display()
    
    
    {
    var target = document.getElementById("function_1");
    var name = document.getElementById("function_2");
    
    if (target == 1)
      {
       var name = "Kachel - Heater";
       name.innerHTML = xDoc.getElementsByTagName("function_2")[0].childNodes[0].nodeValue;
      }
    if (target == 2)
      {
       var name = "Koeling - Cooling";
       name.innerHTML = xDoc.getElementsByTagName("function_2")[0].childNodes[0].nodeValue;
      }
    if (target == 3)
      {
       var name = "Bevochtiger - Humidifier";
       name.innerHTML = xDoc.getElementsByTagName("function_2")[0].childNodes[0].nodeValue;
      }
    if (target == 4)
      {
       var name = "Ontvochtiger - Dehumidifier";
       name.innerHTML = xDoc.getElementsByTagName("function_2")[0].childNodes[0].nodeValue;
      }
    
    };
    

    Or will it be best to go with a different approach completely. Letting the prop itself place the right text in the placeholder with a if if statment , and get the text sended out inside the xml ?
    Thouth the javascript would be a easier fix , thus saving valuable programming space on the prop.
    Any advice ?
  • Mike GMike G Posts: 2,702
    edited 2012-11-16 07:06
    @Igor_Rast, this is what the code is doing.

    1) The variable, name, references the DOM object (html) with id="function_2"
    2) The variable, name, is assigned a string.
    3) The property, name.innerHTML, is assigned to the value of XML node function_2 - Error?

    It looks like the code is trying to do 3 different things with the same variable.

    If you want to write a string to an HTML tag like <div id="mytag"></div> then
      document.getElementById("mytag").innerHTML = "String I want to display";
    
  • Igor_RastIgor_Rast Posts: 357
    edited 2012-11-16 08:10
    Thanks mike , I just figured that one out true w3scools also. though it was a good idea to start to understand it better first .
    so now it looks like this .
    inside the HTML . the div thats gonna hold the text
    [HTML]<div id='interfacebuttons7'></div> [/HTML]

    and using a button to test .
    [HTML]<button type="button" onclick="setting_display()">Try it</button>[/HTML]


    And the script
    [HTML]function setting_display()


    {
    var s= document.getElementById("offset_1").innerHTML;


    if (setting == 01)
    {
    document.getElementById("interfacebuttons7").innerHTML="Kachel";
    };
    if (s == 02)
    {
    document.getElementById("interfacebuttons7").innerHTML="Koeling";
    };
    if (s == 03)
    {
    document.getElementById("interfacebuttons7").innerHTML="Bevochtiger";
    };
    if (s == 04)
    {
    document.getElementById("interfacebuttons7").innerHTML="Ontvochtiger";
    };
    };[/HTML]


    The part of getting the text displayed inside the correct div , looks to be going ok .
    But I think its im not getting the the variable from the function_1 placholder ,. or its not comparring right .
    To do the different actions , putting different names , when the corresponding value is found.
    cant seem to get somewhere with a good explination yet , working on it , Verry appriciate your help

    Now whenever pressed it completes the last statement putting Ontvochtiger" inside the div


    UPDATE .
    I found out what was missing whit reading and testing alot , the ..innerHTML was missing not letting me get the value .
    anyway , I have modified the code above . This is how it does work , getting a name displayed in a div box depending on what value 1-4 it reads out of the xml that gets loaded
  • JavalinJavalin Posts: 892
    edited 2012-11-16 10:04
    Sorted.

    using this code on the client, and a data.xml page returned from the server:
    <!DOCTYPE html>
    <html>
    <head>
    <title>Javalins WebSite</title>
    
    <script type="text/javascript" src="graph.js"></script>
    
    <script>
    
    function DrawGraph(rsXMLPage)
    {
        var i = 0;
        var newArray=new Array();
     
        if (window.XMLHttpRequest)
        {
            // code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp=new XMLHttpRequest();
        }
        else
        {
    	// code for IE6, IE5
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.open("GET",rsXMLPage,false);
        xmlhttp.send();
        xmlDoc=xmlhttp.responseXML;
     
        var DataString = xmlDoc.getElementsByTagName("data")[0].childNodes[0].nodeValue;
        var SplitData = DataString.split(",");
     
        for(i=0;i<SplitData.length;i++)
        {
           newArray[i] = SplitData[i];
        }
    
        g_graph_1 = new Graph(
        {
            'id': "firstgraph",                     // graph
            'strokeStyle': "#1100FF",          	// line colour
            'fillStyle': "rgba(11,0,254,0.25)",     // fill colour
            'showdots': true,               	// Show data points as dots
        	'showgrid': true,               	// Show the grid
        	'showlabels': true,             	// Show labels for each data point
         	'grid': [10,10],                	// X,Y cell width's      
    	'range': [0,100],
    	'data' : function () { return newArray; } ()
        });
    
        document.getElementById("data").innerHTML = 'Latest reading is ' + SplitData[SplitData.length-1];
    }
    </script>
    
    </head>
    
    <body onload="DrawGraph('data.xml');">
    
    <div>
     <b>Data is:</b> <span id="data"></span>
    </div>
    
    <table>
    <tr><th align="center" style="font-family:arial;color:Blue;font-size:20px;">Temperature</th></tr>
    <tr><td><canvas id="firstgraph" width="500" height="200"></canvas></td></tr>
    <tr><th align="center" style="font-family:arial;color:#1100FF;font-size:10px;">(Celcius)</th></tr>
    </table>
    
    </body>
     </html>
    

    Looks like:

    sample1.jpg


    Could be expanded to set parameters for the graph in the xml file, I probably will TBH.

    Cheers!
    1024 x 561 - 28K
  • RforbesRforbes Posts: 281
    edited 2012-11-16 16:18
    @Javalin - That's great! Kudos to you. I'm hoping to sit down and study that a bit!
  • RforbesRforbes Posts: 281
    edited 2012-11-16 16:30
    @Mike- Ok, you're my hero. I've learned a ton in this post alone. But I have another question for ya. (Or anyone else for that matter- I ain't picky!)
    PRI Update_Display(id)|headerOffset,Poker,i
    
        xfds.rxflush              'Empty the buffer incase there's any junk in it.
        Poker:="!"                'Let's poke the other guy!
        xfds.Tx(Poker)            'Poke on the way.
        Level:=xfds.rxTime(10)    'Data coming back at us now. Wait up to 10 ms for the first chunk O' data
        Signal:=xfds.rxTime(10)   'Do it again for the second.
    
        repeat i from 0 to 44     'Get the rest too.
          IOS[i]:=xfds.rxTime(10) 'Wait up to 10ms between each one 'til finished.
               
    
      dynamicContentPtr := @tempBuff                                     'Let's start building our response
      PushDynamicContent(@xmlencode)
      PushDynamicContent(string("<root application='multisocket'>"))   
    
      PushDynamicContent(string("<Level>"))
      str.ToString(@Level, @numBuff)                                            
      PushDynamicContent(@numBuff)
      PushDynamicContent(string("</Level>"))
    
      PushDynamicContent(string("<Signal>"))
      str.ToString(@Signal, @numBuff)                                            
      PushDynamicContent(@numBuff)
      PushDynamicContent(string("</Signal>"))
    
      repeat i from 0 to 42      '<<<======================get's hung up when it's 43 or more (out of stack space or something?)
        PushDynamicContent(string("<IOS"))          'Build some body
        str.ToString(@i, @numBuff)                  'Add some to the body                          
        PushDynamicContent(@numBuff)                'on and on
        PushDynamicContent(string(">"))
        str.ToString(@IOS[i], @numBuff)      
        PushDynamicContent(@numBuff)
        PushDynamicContent(string("</IOS"))
        str.ToString(@i, @numBuff)
        PushDynamicContent(@numBuff)                
        PushDynamicContent(string(">"))             'almost done now 
         PushDynamicContent(string("</root>"))       'Finish up the body
    
        '' Write the header and XML body
      headerOffset := Response.BuildHeader(string("xml"), 200, false)
      Socket.txTCP(id, @txdata, headerOffset)
      StringSend(id, @tempBuff)
        
      bytefill(@tempBuff, 0, TEMP_BUFFER)
      return
    

    In the above code, I can dynamically build the tags IOS0...IOS42. It works fine, with no problem. I'm making my javascript get updates every 3 seconds.
    I am wondering why it stops working when I try to render 43 or more tags?
    At first, I thought maybe I was trying to update from the htm file too quickly, so I changed it to 15 seconds. No difference. Then, I tried to increase the "stackspace[20] to 50 in the HTTPServer object. No dice.

    Can you take a stab and help me understand what I need to do? I eventually need to create about 100 tags. Doing it this way is quite easy, if I can figure out the problem here.

    Thanks in advance
    Robert
  • Mag748Mag748 Posts: 263
    edited 2012-11-16 16:55
    Mike,

    Thanks for posting this information regarding AJAX. I have heard that term many times before, but never knew what it meant, now I know, and I see it to be very useful!

    I was wondering if you knew of a way to "push" data to the client (browser) when new information is available, similar to using this method of AJAX.

    Thanks,
    Marcus
  • Mike GMike G Posts: 2,702
    edited 2012-11-16 17:48
    Can you take a stab and help me understand what I need to do? I eventually need to create about 100 tags. Doing it this way is quite easy, if I can figure out the problem here.
    I believe you need a larger buffer. The temp buffer is 768 bytes; 768/43 = ~18 bytes/node. Otherwise, send the XML body in chunks.
  • Mike GMike G Posts: 2,702
    edited 2012-11-16 18:01
    I was wondering if you knew of a way to "push" data to the client (browser) when new information is available, similar to using this method of AJAX.
    Browsers are not designed to receive "pushed" data. I'm sure it can be done and I can thing of several approaches but not worth the headache.

    It would be a lot easier to write a custom application.
  • Mike GMike G Posts: 2,702
    edited 2012-11-17 06:52
    I was wondering if you knew of a way to "push" data to the client (browser) when new information is available, similar to using this method of AJAX.
    On second thought, broadcast.
  • Igor_RastIgor_Rast Posts: 357
    edited 2012-11-20 04:50
    Though A hint for people that want to use the wiznet on an ipad.

    The xmlhttp POST ( xmlhttp.open("POST","(data to post)",true); ) method doesnt seem to work, with a onclick (button)command to post some data to the wiznet The ipad never sends out the post to the wiznet
    By changing the POST to a GET ( xmlhttp.open("GET","(data to post)",true); ) , it all works fine again . Thouth not the best solution because a GET command is suppose to get some data back , and I only need to post the data to the wiznet to let it do a command.
    But changing them to get did make it all work on the ipad also .
    Never had this problem with computer based brouwsers , there it would work fine with the POST command

    [HTML]function post_to_wiznet()
    {
    var xmlhttp;
    if (window.XMLHttpRequest)
    {// code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();
    }
    else
    {// code for IE6, IE5
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }

    xmlhttp.open("GET","(data to post)",true);
    xmlhttp.send();
    }[/HTML]

    Any rejections to using this method ? or a better way to keep it working on the pc and the ipad withou writing 2 different codes to do the same thing?
  • Mike GMike G Posts: 2,702
    edited 2012-11-20 07:36
    Igor, POST work fine on my ipad.
    Thouth not the best solution because a GET command is suppose to get some data back , and I only need to post the data to the wiznet to let it do a command.
    You are mistaken, both GET and POST return a response. GET sends parameters in the URL while POST sends parameters in the message body.
Sign In or Register to comment.