javascript & Ajax

AJAX stands for Asynchronous JavaScript and XML.
What is AJAX?(web)







若 使用 D1 mini 上的LED 接腳 D5




GPIO2  0  LED亮
GPIO2 1  LED熄


ESP8266 : JavaScript and AJAX


AJAX : working(0:54)(Youtube)(here)




//1. 建立物件
var aReq = new XMLHttpRequest();
//2. 掛上事件處理程式(處理Server response)
aReq.onreadystatechange = function() {
    if (aReq.readyState == XMLHttpRequest.DONE) {
        alert(aReq.responseText);
    }
}
//3. 提出請求
aReq.open('GET', 'url', true);
aReq.send();

AJAX uses JavaScript and is a way for websites to get data without reloading a whole page.

AJAX is a developer's dream, because you can:
1. Update a web page without reloading the page
2. Request data from a server - after the page has loaded
3. Receive data from a server - after the page has loaded
4. Send data to a server - in the background

Using AJAX we can receive and send packets of data behind the scenes either automatically or when an event, like a button click, take places.
e.g. When the button is clicked, instead of loading a whole new page the page will send just the data required to switch the LED.

AJAX Introduction(w3school)








//Example 1
//修改藍色部分
/*
yourRouterSSID
yourRouterPassward
IPGGx-
*/
//開啟手機熱點分享
//打開WiFi搜尋IPGGx-後之IP
//打開瀏覽器連入IP

#include <ESP8266WebServer.h>
#define ssid  "yourRouterSSID"  //手機熱點分享SSID
#define password   "yourRouterPassward" //手機熱點分享密碼
#define LED_Pin  2
ESP8266WebServer server(80);
String html = R"=====(
<!DOCTYPE html>
<html>
 <head>
 <meta name='viewport' content='width=device-width, initial-scale=1.0'/>
 <meta charset='utf-8'>
 <style>
 body {text-align: center;}
 input {font-size: 36px;background-color: #50FF50;}
 p {font-size: 24px;}
 </style>
<script>
var aReq = null;
if (window.XMLHttpRequest)
  { aReq =new XMLHttpRequest(); }
else                       
  { aReq =new ActiveXObject("Microsoft.XMLHTTP"); }

function switchLED()
  {
     var button_text = document.getElementById("LED_button").value;
     if (button_text=="Turn on the LED")
     {
        ajaxLoad('LEDON');
     }
     else if(button_text=="Turn off the LED")
     {
        ajaxLoad('LEDOFF');
     }
    }
function ajaxLoad(ajaxURL)
{
  if(!aReq)
    { alert("AJAX is not supported.");
       return;
    }

  aReq.onreadystatechange = function()
   {
       if(aReq.readyState == XMLHttpRequest.DONE)
        {
         var ajaxResult = aReq.responseText;
        
if ( ajaxResult == "LED is on" ) 
           {
              document.getElementById("LED_button").value = "Turn off the LED";
              document.getElementById("reply").style.color = "#ff0000";
            }
         else if ( ajaxResult == "LED is off" )
           { document.getElementById("LED_button").value = "Turn on the LED";
              document.getElementById("reply").style.color = "#0000ff";
            }
         document.getElementById("reply").innerHTML = ajaxResult;
      }

   }
  aReq.open("GET",ajaxURL,true);
  aReq.send();

}
</script>

 <title>LED Control</title>
</head>
<body>
  <h2>LED Control</h2>
  <input type="button" id = "LED_button" onclick="switchLED()" value="Turn on the LED"  />
  <p id = "reply">Reply appears here</p>
</body>
</html>
 
)=====";

void handleRoot() {
         digitalWrite(LED_Pin,HIGH);
         server.send(200, "text/html", html);
 }

void handleLEDON() {
         digitalWrite(LED_Pin, LOW);
         server.send(200, "text/plain", "LED is on");//esp-->aReq
         /*ESP server送出"LED is on" 給client 端 (由代理人ajaxRequst收)
            即: 代理人aReq  會收到 "LED is on"  (aReq.responseText)
         */
}
void handleLEDOFF() {
         digitalWrite(LED_Pin, HIGH);
         server.send(200, "text/plain", "LED is off");
}

void setup()
{
    pinMode(LED_Pin, OUTPUT);    
    digitalWrite(LED_Pin,HIGH);
    WiFi.begin(ssid,password);
     while (WiFi.status() != WL_CONNECTED)
    {     
        delay(500);
    }
   WiFi.mode(WIFI_AP_STA);
    WiFi.softAP(String("IPGGx-"+ String((WiFi.localIP().toString()))),"");   
    digitalWrite(LED_Pin,LOW);   
    server.on("/", handleRoot);
    server.on("/LEDON", handleLEDON);
    server.on("/LEDOFF", handleLEDOFF);  
    server.begin();
   
 
}

void loop() {
 server.handleClient();
}


程式執行流程:
1. browser 輸入 192.168.xxx.xxx   (espIP)
    根據server.on("/", handleRoot); 交由handleRoot()處理:請求ESP server 送出網頁

2. click button -->觸發onclick 根據:
    <input type="button" id = "LED_button" onclick="switchLED()" value="Turn on the LED"  /> 交由  switchLED()  處理

3. switch():取得目前button上的字-->"Turn on the LED"
    執行: ajaxLoad('LEDON');
   
     aReq.open("GET",'LEDON',true);
     aReq.send();

     送出
LEDON給ESP server 相當於在網址列輸入 http://espIP/LEDON
4. ESP server 收到
espIP\LEDON  根據:  server.on("/LEDON", handleLEDON);
    交由handleLEDON()處理:
     1. ESP server 將LED_Pin (GPIO2)設為低電位(點亮)
         digitalWrite(LED_Pin, LOW);
     2. ESP server送出"LED is on" 給client
         server.send(200, "text/plain", "LED is on");
5. esp server 送出LED is on 觸發client 端  aReq.onreadystatechange 事件
     由aReq.onreadystatechange = function(){....} 處理
     此時 ajaxResult == "LED is on"
     1. 將button 字改為:
"Turn off the LED"
     2. 將回應字style.color 改為紅色
     3. 將回應字改為:LED is on

       
2a. click button -->觸發onclick 根據:
    <input type="button" id = "LED_button" onclick="switchLED()" value="Turn on the LED"  /> 交由  switchLED()  處理


3a. switch():取得目前button上的字-->"Turn off the LED"
    執行: ajaxLoad('LEDOFF');
   

     aReq.open("GET",'LEDOFF',true);
     aReq.send();

    
送出LEDOFF給ESP server 相當於在網址列輸入 http://espIP/LEDOFF
4a. ESP server 收到
espIP\LEDOFF  根據:  server.on("/LEDOFF", handleLEDOFF);
    交由handleLEDOFF()處理:
     1. ESP server 將LED_Pin (GPIO2)設為高電位(熄滅)
         digitalWrite(LED_Pin, HIGH);
     2. ESP server送出"LED is off" 給client
         server.send(200, "text/plain", "LED is off");

5a.
esp server 送出LED is off 觸發client 端  aReq.onreadystatechange 事件
     由aReq.onreadystatechange = function(){....} 處理
     此時
ajaxResult == "LED is off"
     1. 將button 字改為:
"Turn on the LED"
     2. 將回應字style.color 改為藍色
     3. 將回應字改為:LED is off

    




javascript說明

String html = R"=====(
<!DOCTYPE html>
<html>
 <head>
 <meta name='viewport' content='width=device-width, initial-scale=1.0'/>
 <meta charset='utf-8'>
 <style>
 body {text-align: center;}
 input {font-size: 36px;background-color: #50FF50;}
 p {font-size: 24px;}
 </style>

<script>
var aReq = null;
if (window.XMLHttpRequest)
  { aReq =new XMLHttpRequest(); }
else                       
  { aReq =new ActiveXObject("Microsoft.XMLHTTP"); }


function switchLED()
  { /*取得button 上的字*/
     var button_text = document.getElementById("LED_button").value;
     if (button_text=="Turn on the LED")
     {
        ajaxLoad('LEDON');
     }
     else if(button_text=="Turn off the LED")
     {
        ajaxLoad('LEDOFF');
     }
    }
function ajaxLoad(ajaxURL)
{
  if(!aReq)
    { alert("AJAX is not supported.");
       return;
    }

 
//掛上onreadystatechange event 服務程式(取得server傳來的資料 更新HTML)
  aReq.onreadystatechange = function()
   {
       if(aReq.readyState == XMLHttpRequest.DONE)
     //if(aReq.readyState == 4 && aReq.status==200)
       {/* 取得server 送來的資料 */
         var ajaxResult = aReq.responseText;
        
/*update HTML*/
         if ( ajaxResult == "LED is on" ) 
           {
              document.getElementById("LED_button").value = "Turn off the LED";
              document.getElementById("reply").style.color = "#ff0000";
            }
         else if ( ajaxResult == "LED is off" )
           { document.getElementById("LED_button").value = "Turn on the LED";
              document.getElementById("reply").style.color = "#0000ff";
            }
         document.getElementById("reply").innerHTML = ajaxResult;
      }

   }
//Specifies the type of request 
  aReq.open("GET",ajaxURL,true);
   //打開通道
//Sends the request to the server (used for GET)
  aReq.send();
//送出請求  aReq-->ESP server
}
</script>

 <title>LED Control</title>
</head>
<body>
  <h2>LED Control</h2>
  <input type="button" id = "LED_button" onclick="switchLED()" value="Turn on the LED"  />
  <p id = "reply">Reply appears here</p>
</body>
</html>
 
)=====";



JavaScript has a function called onClick().
This can be attached to elements to capture the click event (mouse click). Add this to the button.


<input type="button" id = "LED_button" onclick="switchLED()" value="Turn on the LED"  />

When the button is clicked the onClick() function is called which in turn calls another function called switchLED().

input type="button" id = "LED_button" onclick="switchLED()" value="Turn on the LED" />

function switchLED()
  {
       var button_text = document.getElementById("LED_button").value;
     if (button_text=="Turn on the LED")
     {
       document.getElementById("LED_button").value = "Turn off the LED";
       ajaxLoad('LEDON');
     }
     else
     {
       document.getElementById("LED_button").value = "Turn on the LED";
       ajaxLoad('LEDOFF');
     }
  }

switchLED()
1. changes the button text (on to off or off to on)
2. sends the LED control code to the function called ajaxLoad().


All modern browsers support the XMLHttpRequest object.
The XMLHttpRequest object can be used to exchange data with a server behind the scenes.
This means that it is possible to update parts of a web page, without reloading the whole page.
//Example:
//Create an XMLHttpRequest Object

var aReq = null;
if (window.XMLHttpRequest)
// code for modern browsers 
   { aReq =new XMLHttpRequest(); }
else
// code for old IE browsers
   { aReq =new ActiveXObject("Microsoft.XMLHTTP"); }

//(ref)


The ajaxLoad() function is where the AJAX action takes place.
The request is made to the ESP8266 server.

Called in function switchLED() ,
ajaxLoad('LEDON');
ajaxLoad('LEDOFF');

//Ajax 代理HTTP web 向ESP server 提出請求
function ajaxLoad(ajaxURL)
{
  aReq.open("GET",ajaxURL,true);
  aReq.send();
}


aReq.open("GET",ajaxURL,true);

Opens the request channel using GET (the other option is PUT).
ajaxURL is the URL or at least the bit to be added to the url.
In this case it is the LED control code.('LEDON' or 'LEDOFF')

The last value “true” means use an asynchronous request. “false” would mean use a synchronous request.
Synchronous requests block the browser (they stop everything until they get a reply).
Asynchronous requests don’t block, they allow the browser to do other things while waiting for a the reply.


aReq.open("GET",ajaxURL,true);

open(method,url,async,user,psw)
Specifies the request
method: the request type GET or POST
url: the file location
async: true (asynchronous) or false (synchronous)
user: optional user name
psw: optional password

Send a Request To a Server(W3School)

aReq.open("GET",'LEDON',true);
aReq.send();
相當於
在瀏覽器中向伺服器送出 http://IP/LEDON


Ajax 代理Client端 接收由ESP server 傳來之資料
The onreadystatechange Property(W3school)


When a reply is received, the onreadystatechange flag is set which triggers the following.


aReq.onreadystatechange = function()
  {
    if(aReq.readyState == XMLHttpRequest.DONE)
    //if(aReq.readyState == 4 && aReq.status==200)
    {
      var ajaxResult = aReq.responseText;
    }

Here the reply is checked.
A readyState of 4 means the request has finished and a response is ready.
A status of 200 means the request was OK.
This is the standard status code.



var ajaxResult = aReq.responseText;

The response from the server is assigned to the ajaxResult variable.


使用mDNS (Multicast DNS)
多播DNS(mDNS)提供在沒有任何傳統單播DNS伺服器的情況下在本地鏈路上執行類似DNS的操作的能力。此外,多播DNS指定DNS名稱空間的一部分可供本地使用,無需支付任何年費,也無需設定授權或以其他方式配置傳統DNS伺服器來回答這些名稱。



//Example 2
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#define ssid  "yourRouterSSID"
#define password   "yourRouterPassward"
#define LED_Pin  2
#define mDns "espggx" 
ESP8266WebServer server(80);
MDNSResponder mdns;
String html = R"=====(
<!DOCTYPE html>
<html>
 <head>
 <meta name='viewport' content='width=device-width, initial-scale=1.0'/>
 <meta charset='utf-8'>
 <style>
 body {text-align: center;}
 input {font-size: 36px;background-color: #50FF50;}
 p {font-size: 24px;}
 </style>

<script>
 

var aReq = null;
if (window.XMLHttpRequest)
  { aReq =new XMLHttpRequest(); }
else                      
  { aReq =new ActiveXObject("Microsoft.XMLHTTP"); }


function switchLED()
  {
     var button_text = document.getElementById("LED_button").value;
     if (button_text=="Turn on the LED")
     {
        ajaxLoad('LEDON');
     }
     else
     {
        ajaxLoad('LEDOFF');
     }
    }
function ajaxLoad(ajaxURL)
{
  if(!aReq)
    { alert("AJAX is not supported.");
       return;
    }
   aReq.onreadystatechange = function()
   {
       if(aReq.readyState == XMLHttpRequest.DONE)
        {
         var ajaxResult = aReq.responseText;
         if ( ajaxResult == "LED is on" )
           {
              document.getElementById("LED_button").value = "Turn off the LED";
              document.getElementById("reply").style.color = "#ff0000";
            }
         else if ( ajaxResult == "LED is off" )
           { document.getElementById("LED_button").value = "Turn on the LED";
              document.getElementById("reply").style.color = "#0000ff";
            }
         document.getElementById("reply").innerHTML = ajaxResult;
      }
   }
 aReq.open("GET",ajaxURL,true);  
 aReq.send(); //aReq-->ESP server
}
</script>

 <title>LED Control</title>
</head>
<body>
  <h2>LED Control</h2>
  <input type="button" id = "LED_button" onclick="switchLED()" value="Turn on the LED"  />
  <p id = "reply">Reply appears here</p>
</body>
</html>
 
)=====";


void handleRoot() {
         digitalWrite(LED_Pin,HIGH);
         server.send(200, "text/html", html);
 }

void handleLEDON() {
         digitalWrite(LED_Pin, LOW);
         /*ESP server送出"LED is on" 給client 代理人ajaxRequst
            aReq  會收到 "LED is on" ---> aReq.responseText
         */
         server.send(200, "text/plain", "LED is on");//esp-->aReq
}
void handleLEDOFF() {
         digitalWrite(LED_Pin, HIGH);
         server.send(200, "text/plain", "LED is off");
}

void setup()
{
    pinMode(LED_Pin, OUTPUT);   
    digitalWrite(LED_Pin,HIGH);
    WiFi.begin(ssid,password);
     while (WiFi.status() != WL_CONNECTED)
    {    
        delay(500);
    }
    mdns.begin(mDns, WiFi.localIP());
   WiFi.mode(WIFI_AP_STA);
    WiFi.softAP(String("IPGGx-"+ String((WiFi.localIP().toString()))),"");
    MDNS.begin(mDns); 
    digitalWrite(LED_Pin,LOW);  
    server.on("/", handleRoot);
    server.on("/LEDON", handleLEDON);
    server.on("/LEDOFF", handleLEDOFF); 
    server.begin();
  
 
} // void setup()

void loop() {
  mdns.update();
 server.handleClient();
}

//使用mDNS連線 (Android作業系統不支援mDNS)
//http://espggx.local