NodeMCU Ajax Enabled Web Server

Posted on

by

in

ESP8266 NodeMCU Web Server: No Page Refresh using AJAX and Javascript

If you have been observant in my previous post about controlling your components using your mobile phone then you might have noticed that the page “flickers” whenever we “toggle” the button for the LED and the Buzzer. It is because the page is being submitted as a whole to our NodeMCU ESP8266 WebServer and you are being redirected to a new page. In this post, we will remove that “flickering” so that no page refresh will happen using Asynchronous Javascript and XML (AJAX) and Javascript.

If you want to see this project in a video format then please see below. You can also watch this on my YouTube channel.

Why is the page ‘flickering?’

You might be confused with all the terms so let us see everything in slow motion. First, we access our Web Server using the IP Address assigned by our wifi router so that we can access our application. We are able to access our application by typing the IP Address in our browser.

NodeMCU Webserver Root Page

Next, when you toggle or slide the LED button from OFF to ON you might have noticed that the URL in the browser has changed.

Webserver Page Toggle LED

Look closely and you would notice that from the original URL which is “192.168.100.14” it is now “192.168.100.14/toggleLED”. In this case, our NodeMCU ESP8266 Web server is showing you a different html page although it looks the same.

This applies also to our buzzer of which you would notice that the URL changes from “192.168.100.14” to “192.168.100.14/toggleBuzzer”. Look closely again at the demo video.

This is the reason why your page is “flickering”. The browser is transitioning from one page to the other. It is almost similar to when you type “google.com” and enter your search keys. The result would return back and you click the link of the results. The browser will forward you to a new URL.

But in our case you want your page URL to remain the same but you wanted parts of your page to get updated whenever you click something. That is where AJAX or XMLHttpRequest comes in the browser. Say for example you want to read a temperature sensor and display its real-time values. You can do this by clicking refresh on your browser so that it would retrieve the latest value from the sensor. But it is not what you want. So we will utilize the XMLHttpRequest API to send an HTTP request from our browser to our NodeMCU ESP8266 Web Server.

Wiring Diagram

ESP8266 NodeMCU Web Server

Note: No changes from our previous wiring diagram

ESP8266 WebServer AJAX Code

The complete code for my project is in my GitHub account and you can see it here. Let us look first at what changes we need for our html page to make our NodeMCU ESP8266 WebServer AJAX enabled.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title>NodeMCU ESP8266 Web Server</title>
		<style>
			/* Copyright 2014 Owen Versteeg; MIT licensed */body,textarea,input,select{background:0;border-radius:0;font:16px sans-serif;margin:0}.smooth{transition:all .2s}.btn,.nav a{text-decoration:none}.container{margin:0 20px;width:auto}label>*{display:inline}form>*{display:block;margin-bottom:10px}.btn{background:#999;border-radius:6px;border:0;color:#fff;cursor:pointer;display:inline-block;margin:2px 0;padding:12px 30px 14px}.btn:hover{background:#888}.btn:active,.btn:focus{background:#777}.btn-a{background:#0ae}.btn-a:hover{background:#09d}.btn-a:active,.btn-a:focus{background:#08b}.btn-b{background:#3c5}.btn-b:hover{background:#2b4}.btn-b:active,.btn-b:focus{background:#2a4}.btn-c{background:#d33}.btn-c:hover{background:#c22}.btn-c:active,.btn-c:focus{background:#b22}.btn-sm{border-radius:4px;padding:10px 14px 11px}.row{margin:1% 0;overflow:auto}.col{float:left}.table,.c12{width:100%}.c11{width:91.66%}.c10{width:83.33%}.c9{width:75%}.c8{width:66.66%}.c7{width:58.33%}.c6{width:50%}.c5{width:41.66%}.c4{width:33.33%}.c3{width:25%}.c2{width:16.66%}.c1{width:8.33%}h1{font-size:3em}.btn,h2{font-size:2em}.ico{font:33px Arial Unicode MS,Lucida Sans Unicode}.addon,.btn-sm,.nav,textarea,input,select{outline:0;font-size:14px}textarea,input,select{padding:8px;border:1px solid #ccc}textarea:focus,input:focus,select:focus{border-color:#5ab}textarea,input[type=text]{-webkit-appearance:none;width:13em}.addon{padding:8px 12px;box-shadow:0 0 0 1px #ccc}.nav,.nav .current,.nav a:hover{background:#000;color:#fff}.nav{height:24px;padding:11px 0 15px}.nav a{color:#aaa;padding-right:1em;position:relative;top:-1px}.nav .pagename{font-size:22px;top:1px}.btn.btn-close{background:#000;float:right;font-size:25px;margin:-54px 7px;display:none}@media(min-width:1310px){.container{margin:auto;width:1270px}}@media(max-width:870px){.row .col{width:100%}}@media(max-width:500px){.btn.btn-close{display:block}.nav{overflow:hidden}.pagename{margin-top:-11px}.nav:active,.nav:focus{height:auto}.nav div:before{background:#000;border-bottom:10px double;border-top:3px solid;content:'';float:right;height:4px;position:relative;right:3px;top:14px;width:20px}.nav a{padding:.5em 0;display:block;width:50%}}.table th,.table td{padding:.5em;text-align:left}.table tbody>:nth-child(2n-1){background:#ddd}.msg{padding:1.5em;background:#def;border-left:5px solid #59d}
			.hero {
				background: #eee;
				padding: 20px;
				border-radius: 10px;
				margin-top: 1em;
			}

			.hero h1 {
				margin-top: 0;
				margin-bottom: 0.3em;
			}

			.c4 {
				padding: 10px;
				box-sizing: border-box;
			}

			.c4 h3 {
				margin-top: 0;
			}
			
			// Code from https://proto.io/freebies/onoff/
			.c4 a {
				margin-top: 10px;
				display: inline-block;
			}
			
			.onoffswitch {
				position: relative; width: 90px;
				-webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
			}
			.onoffswitch-checkbox {
				position: absolute;
				opacity: 0;
				pointer-events: none;
			}
			.onoffswitch-label {
				display: block; overflow: hidden; cursor: pointer;
				border: 2px solid #999999; border-radius: 20px;
			}
			.onoffswitch-inner {
				display: block; width: 200%; margin-left: -100%;
				transition: margin 0.3s ease-in 0s;
			}
			.onoffswitch-inner:before, .onoffswitch-inner:after {
				display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;
				font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
				box-sizing: border-box;
			}
			.onoffswitch-inner:before {
				content: "ON";
				padding-left: 10px;
				background-color: #34A7C1; color: #FFFFFF;
			}
			.onoffswitch-inner:after {
				content: "OFF";
				padding-right: 10px;
				background-color: #EEEEEE; color: #999999;
				text-align: right;
			}
			.onoffswitch-switch {
				display: block; width: 18px; margin: 6px;
				background: #FFFFFF;
				position: absolute; top: 0; bottom: 0;
				right: 56px;
				border: 2px solid #999999; border-radius: 20px;
				transition: all 0.3s ease-in 0s; 
			}
			.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
				margin-left: 0;
			}
			.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
				right: 0px; 
			}
			
			.grid-container {
				display: grid;
				grid-template-columns: 1fr 1fr;
				grid-gap: 20px;
			}
			
			.flex-container {
				display: flex;
				margin-top: 40px;
			}

			.flex-child {
				flex: 1;
				//border: 2px solid yellow;
			}  

			.flex-child:first-child {
				margin-right: 20px;
			} 
			
			.component-label{
				float: right;
				font-weight: bold;
				font-size: 25px;
			}
		</style>
	</head>
	<body>
		<nav class="nav" tabindex="-1" onclick="this.focus()">
			<div class="container">
				<a class="pagename current" href="#">wwww.donskytech.com</a>
			</div>
		</nav>
		<button class="btn-close btn btn-sm">×</button>
		<div class="container">
			<div class="hero">
				<h1>NodeMCU ESP8266 Web Server</h1>
				<div class="flex-container">
				  <div class="flex-child magenta">
					<span class="component-label">LED</span>
				  </div>
				  <div class="flex-child green">
					<div class="grid-child green">
						<div style="display: inline">
							<div class="onoffswitch">
								<input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="ledSwitch" tabindex="0">
								<label class="onoffswitch-label" for="ledSwitch">
									<span class="onoffswitch-inner"></span>
									<span class="onoffswitch-switch"></span>
								</label>
							</div>
						</div>
					</div>
				  </div>
				</div>
				<div class="flex-container">
				  <div class="flex-child magenta">
					<span class="component-label">Buzzer</span>
				  </div>
				  <div class="flex-child green">
					<div class="grid-child green">
						<div style="display: inline">
							<div class="onoffswitch">
								<input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="buzzerSwitch" tabindex="0">
								<label class="onoffswitch-label" for="buzzerSwitch">
									<span class="onoffswitch-inner"></span>
									<span class="onoffswitch-switch"></span>
								</label>
							</div>
						</div>
					</div>
				  </div>
				</div>
			</div>
		</div>
		<script>
			document.getElementById('ledSwitch').onclick = function() {
				// access properties using this keyword
				var ledStatus;
				if ( this.checked ) {
					ledStatus = "ON";
				} else {
					ledStatus = "OFF";
				}
				var xhttp = new XMLHttpRequest();
				xhttp.onreadystatechange = function() {
					if (this.readyState == 4 && this.status == 200) {
						console.log("Successfully received ");
					}
				};
				xhttp.open("GET", "toggleLED?ledStatus="+ledStatus, true);
				xhttp.send();
			};
			document.getElementById('buzzerSwitch').onclick = function() {
				// access properties using this keyword
				var buzzerStatus;
				if ( this.checked ) {
					buzzerStatus = "ON";
				} else {
					buzzerStatus = "OFF";
				}
				var xhttp = new XMLHttpRequest();
				xhttp.onreadystatechange = function() {
					if (this.readyState == 4 && this.status == 200) {
						
					}
				};
				xhttp.open("GET", "toggleBuzzer?buzzerStatus="+buzzerStatus, true);
				xhttp.send();
			};
		</script>
	</body>
</html>

The code remains the same from our previous post but the only change is in this line.

</div>
        <script>
            document.getElementById('ledSwitch').onclick = function() {
                // access properties using this keyword
                var ledStatus;
                if ( this.checked ) {
                    ledStatus = "ON";
                } else {
                    ledStatus = "OFF";
                }
                var xhttp = new XMLHttpRequest();
                xhttp.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        console.log("Successfully received ");
                    }
                };
                xhttp.open("GET", "toggleLED?ledStatus="+ledStatus, true);
                xhttp.send();
            };
            document.getElementById('buzzerSwitch').onclick = function() {
                // access properties using this keyword
                var buzzerStatus;
                if ( this.checked ) {
                    buzzerStatus = "ON";
                } else {
                    buzzerStatus = "OFF";
                }
                var xhttp = new XMLHttpRequest();
                xhttp.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                         
                    }
                };
                xhttp.open("GET", "toggleBuzzer?buzzerStatus="+buzzerStatus, true);
                xhttp.send();
            };
        </script>
    </body>
</html>

We added a bit of javascript to our html page so that when the user clicks or toggles the button then we are going to send an XMLHttpRequest to our NodeMCU ESP8266 Web Server.

                var xhttp = new XMLHttpRequest();
                xhttp.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        console.log("Successfully received ");
                    }
                };
                xhttp.open("GET", "toggleLED?ledStatus="+ledStatus, true);
                xhttp.send();

The important line of the code is this. It will call the “toggleLED” URL endpoint using an HTTP Get Request and adding a parameter if it is either “ON” or “OFF”. A handler function is associated with this in our Arduino IDE code to respond to this. This line of code is how we can make our NodeMCU ESP8266 WebServer AJAX enabled. This will make our User Interface more responsive.

The code for our NodeMCU ESP8266 is below.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>


/********** PLEASE CHANGE THIS *************************/
const char* ssid     = "<ENTER YOUR WIFI SSID>";
const char* password = "<ENTER YOUR PASSWORD>";

ESP8266WebServer server(80);

uint8_t LEDPin = D7;
bool LEDStatus = LOW;

uint8_t buzzerPin = D1;
bool buzzerStatus = LOW;

void setup() {
  Serial.begin(115200);
  pinMode(LEDPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);

  Serial.println("Connecting to ");
  Serial.println(ssid);

  //connect to your local wi-fi network
  WiFi.begin(ssid, password);

  //check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/toggleLED", updateLED);
  server.on("/toggleBuzzer", updateBuzzerSound);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
}

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

void updateLED() {
  String ledStatusParam = server.arg("ledStatus");
  if (ledStatusParam == "ON")
    LEDStatus =  HIGH;
  else
    LEDStatus =  LOW;
  digitalWrite(LEDPin, LEDStatus);

  server.send(200, "text/plain", "Success!");
}

void updateBuzzerSound() {
  String buzzerStatusParam = server.arg("buzzerStatus");
  if (buzzerStatusParam == "ON")
    buzzerStatus =  HIGH;
  else
    buzzerStatus =  LOW;

  if (buzzerStatus)
    tone(buzzerPin, 1200);
  else
    noTone(buzzerPin);

  server.send(200, "text/plain", "Success!");
}

void handleNotFound() {
  server.send(404, "text/plain", "Not found");
}

String prepareHTML() {
  // BuildMyString.com generated code. Please enjoy your string responsibly.

  String html = "<!DOCTYPE html>\n"
                "<html>\n"
                "  <head>\n"
                "   <meta charset=\"UTF-8\">\n"
                "   <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
                "   <title>NodeMCU ESP8266 Web Server</title>\n"
                "   <style>\n"
                "     /* Copyright 2014 Owen Versteeg; MIT licensed */body,textarea,input,select{background:0;border-radius:0;font:16px sans-serif;margin:0}.smooth{transition:all .2s}.btn,.nav a{text-decoration:none}.container{margin:0 20px;width:auto}label>*{display:inline}form>*{display:block;margin-bottom:10px}.btn{background:#999;border-radius:6px;border:0;color:#fff;cursor:pointer;display:inline-block;margin:2px 0;padding:12px 30px 14px}.btn:hover{background:#888}.btn:active,.btn:focus{background:#777}.btn-a{background:#0ae}.btn-a:hover{background:#09d}.btn-a:active,.btn-a:focus{background:#08b}.btn-b{background:#3c5}.btn-b:hover{background:#2b4}.btn-b:active,.btn-b:focus{background:#2a4}.btn-c{background:#d33}.btn-c:hover{background:#c22}.btn-c:active,.btn-c:focus{background:#b22}.btn-sm{border-radius:4px;padding:10px 14px 11px}.row{margin:1% 0;overflow:auto}.col{float:left}.table,.c12{width:100%}.c11{width:91.66%}.c10{width:83.33%}.c9{width:75%}.c8{width:66.66%}.c7{width:58.33%}.c6{width:50%}.c5{width:41.66%}.c4{width:33.33%}.c3{width:25%}.c2{width:16.66%}.c1{width:8.33%}h1{font-size:3em}.btn,h2{font-size:2em}.ico{font:33px Arial Unicode MS,Lucida Sans Unicode}.addon,.btn-sm,.nav,textarea,input,select{outline:0;font-size:14px}textarea,input,select{padding:8px;border:1px solid #ccc}textarea:focus,input:focus,select:focus{border-color:#5ab}textarea,input[type=text]{-webkit-appearance:none;width:13em}.addon{padding:8px 12px;box-shadow:0 0 0 1px #ccc}.nav,.nav .current,.nav a:hover{background:#000;color:#fff}.nav{height:24px;padding:11px 0 15px}.nav a{color:#aaa;padding-right:1em;position:relative;top:-1px}.nav .pagename{font-size:22px;top:1px}.btn.btn-close{background:#000;float:right;font-size:25px;margin:-54px 7px;display:none}@media(min-width:1310px){.container{margin:auto;width:1270px}}@media(max-width:870px){.row .col{width:100%}}@media(max-width:500px){.btn.btn-close{display:block}.nav{overflow:hidden}.pagename{margin-top:-11px}.nav:active,.nav:focus{height:auto}.nav div:before{background:#000;border-bottom:10px double;border-top:3px solid;content:'';float:right;height:4px;position:relative;right:3px;top:14px;width:20px}.nav a{padding:.5em 0;display:block;width:50%}}.table th,.table td{padding:.5em;text-align:left}.table tbody>:nth-child(2n-1){background:#ddd}.msg{padding:1.5em;background:#def;border-left:5px solid #59d}\n"
                "     .hero {\n"
                "       background: #eee;\n"
                "       padding: 20px;\n"
                "       border-radius: 10px;\n"
                "       margin-top: 1em;\n"
                "     }\n"
                "     .hero h1 {\n"
                "       margin-top: 0;\n"
                "       margin-bottom: 0.3em;\n"
                "     }\n"
                "     .c4 {\n"
                "       padding: 10px;\n"
                "       box-sizing: border-box;\n"
                "     }\n"
                "     .c4 h3 {\n"
                "       margin-top: 0;\n"
                "     }\n"
                "     \n"
                "     // Code from https://proto.io/freebies/onoff/\n"
                "     .c4 a {\n"
                "       margin-top: 10px;\n"
                "       display: inline-block;\n"
                "     }\n"
                "     \n"
                "     .onoffswitch {\n"
                "       position: relative; width: 90px;\n"
                "       -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;\n"
                "     }\n"
                "     .onoffswitch-checkbox {\n"
                "       position: absolute;\n"
                "       opacity: 0;\n"
                "       pointer-events: none;\n"
                "     }\n"
                "     .onoffswitch-label {\n"
                "       display: block; overflow: hidden; cursor: pointer;\n"
                "       border: 2px solid #999999; border-radius: 20px;\n"
                "     }\n"
                "     .onoffswitch-inner {\n"
                "       display: block; width: 200%; margin-left: -100%;\n"
                "       transition: margin 0.3s ease-in 0s;\n"
                "     }\n"
                "     .onoffswitch-inner:before, .onoffswitch-inner:after {\n"
                "       display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;\n"
                "       font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;\n"
                "       box-sizing: border-box;\n"
                "     }\n"
                "     .onoffswitch-inner:before {\n"
                "       content: \"ON\";\n"
                "       padding-left: 10px;\n"
                "       background-color: #34A7C1; color: #FFFFFF;\n"
                "     }\n"
                "     .onoffswitch-inner:after {\n"
                "       content: \"OFF\";\n"
                "       padding-right: 10px;\n"
                "       background-color: #EEEEEE; color: #999999;\n"
                "       text-align: right;\n"
                "     }\n"
                "     .onoffswitch-switch {\n"
                "       display: block; width: 18px; margin: 6px;\n"
                "       background: #FFFFFF;\n"
                "       position: absolute; top: 0; bottom: 0;\n"
                "       right: 56px;\n"
                "       border: 2px solid #999999; border-radius: 20px;\n"
                "       transition: all 0.3s ease-in 0s; \n"
                "     }\n"
                "     .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {\n"
                "       margin-left: 0;\n"
                "     }\n"
                "     .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {\n"
                "       right: 0px; \n"
                "     }\n"
                "     \n"
                "     .grid-container {\n"
                "       display: grid;\n"
                "       grid-template-columns: 1fr 1fr;\n"
                "       grid-gap: 20px;\n"
                "     }\n"
                "     \n"
                "     .flex-container {\n"
                "       display: flex;\n"
                "       margin-top: 40px;\n"
                "     }\n"
                "     .flex-child {\n"
                "       flex: 1;\n"
                "       //border: 2px solid yellow;\n"
                "     }  \n"
                "     .flex-child:first-child {\n"
                "       margin-right: 20px;\n"
                "     } \n"
                "     \n"
                "     .component-label{\n"
                "       float: right;\n"
                "       font-weight: bold;\n"
                "       font-size: 25px;\n"
                "     }\n"
                "   </style>\n"
                " </head>\n"
                " <body>\n"
                "   <nav class=\"nav\" tabindex=\"-1\" onclick=\"this.focus()\">\n"
                "     <div class=\"container\">\n"
                "       <a class=\"pagename current\" href=\"#\">wwww.donskytech.com</a>\n"
                "     </div>\n"
                "   </nav>\n"
                "\n"
                "   <div class=\"container\">\n"
                "     <div class=\"hero\">\n"
                "       <h1>NodeMCU ESP8266 Web Server</h1>\n"
                "       <div class=\"flex-container\">\n"
                "         <div class=\"flex-child magenta\">\n"
                "         <span class=\"component-label\">LED</span>\n"
                "         </div>\n"
                "         <div class=\"flex-child green\">\n"
                "         <div class=\"grid-child green\">\n"
                "           <div style=\"display: inline\">\n"
                "             <div class=\"onoffswitch\">\n"
                "               <input type=\"checkbox\" name=\"onoffswitch\" class=\"onoffswitch-checkbox\" id=\"ledSwitch\" tabindex=\"0\">\n"
                "               <label class=\"onoffswitch-label\" for=\"ledSwitch\">\n"
                "                 <span class=\"onoffswitch-inner\"></span>\n"
                "                 <span class=\"onoffswitch-switch\"></span>\n"
                "               </label>\n"
                "             </div>\n"
                "           </div>\n"
                "         </div>\n"
                "         </div>\n"
                "       </div>\n"
                "       <div class=\"flex-container\">\n"
                "         <div class=\"flex-child magenta\">\n"
                "         <span class=\"component-label\">Buzzer</span>\n"
                "         </div>\n"
                "         <div class=\"flex-child green\">\n"
                "         <div class=\"grid-child green\">\n"
                "           <div style=\"display: inline\">\n"
                "             <div class=\"onoffswitch\">\n"
                "               <input type=\"checkbox\" name=\"onoffswitch\" class=\"onoffswitch-checkbox\" id=\"buzzerSwitch\" tabindex=\"0\">\n"
                "               <label class=\"onoffswitch-label\" for=\"buzzerSwitch\">\n"
                "                 <span class=\"onoffswitch-inner\"></span>\n"
                "                 <span class=\"onoffswitch-switch\"></span>\n"
                "               </label>\n"
                "             </div>\n"
                "           </div>\n"
                "         </div>\n"
                "         </div>\n"
                "       </div>\n"
                "     </div>\n"
                "   </div>\n"
                "   <script>\n"
                "     document.getElementById('ledSwitch').onclick = function() {\n"
                "       // access properties using this keyword\n"
                "       var ledStatus;\n"
                "       if ( this.checked ) {\n"
                "         ledStatus = \"ON\";\n"
                "       } else {\n"
                "         ledStatus = \"OFF\";\n"
                "       }\n"
                "       var xhttp = new XMLHttpRequest();\n"
                "       xhttp.onreadystatechange = function() {\n"
                "         if (this.readyState == 4 && this.status == 200) {\n"
                "           console.log(\"Successfully received \");\n"
                "         }\n"
                "       };\n"
                "       xhttp.open(\"GET\", \"toggleLED?ledStatus=\"+ledStatus, true);\n"
                "       xhttp.send();\n"
                "     };\n"
                "     document.getElementById('buzzerSwitch').onclick = function() {\n"
                "       // access properties using this keyword\n"
                "       var buzzerStatus;\n"
                "       if ( this.checked ) {\n"
                "         buzzerStatus = \"ON\";\n"
                "       } else {\n"
                "         buzzerStatus = \"OFF\";\n"
                "       }\n"
                "       var xhttp = new XMLHttpRequest();\n"
                "       xhttp.onreadystatechange = function() {\n"
                "         if (this.readyState == 4 && this.status == 200) {\n"
                "           \n"
                "         }\n"
                "       };\n"
                "       xhttp.open(\"GET\", \"toggleBuzzer?buzzerStatus=\"+buzzerStatus, true);\n"
                "       xhttp.send();\n"
                "     };\n"
                "   </script>\n"
                " </body>\n"
                "</html>\n";


  return html;
}

The code almost remains the same as in our previous post and I am highlighting only the relevant changes.

void updateLED() {
  String ledStatusParam = server.arg("ledStatus");
  if (ledStatusParam == "ON")
    LEDStatus =  HIGH;
  else
    LEDStatus =  LOW;
  digitalWrite(LEDPin, LEDStatus);
 
  server.send(200, "text/plain", "Success!");
}
 
void updateBuzzerSound() {
  String buzzerStatusParam = server.arg("buzzerStatus");
  if (buzzerStatusParam == "ON")
    buzzerStatus =  HIGH;
  else
    buzzerStatus =  LOW;
 
  if (buzzerStatus)
    tone(buzzerPin, 1200);
  else
    noTone(buzzerPin);
 
  server.send(200, "text/plain", "Success!");
}
  • Line 2 – We extract the value of the LEDStatus from the javascript code that we entered.
  • Line 3-6 – We check if the passed parameter is “ON” or “OFF” from our javascript code then we set the LEDStatus variable appropriately.
  • Line 7 – We turn on or off the LED depending on the passed parameter
  • Line 9 – We send back a message to our javascript handler.

Our prepareHTML() function has now changed also as we do not need to do an “if/else” logic in here anymore. This function only gets called once also and is only called in the handleRoot()

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

The prepareHTML() function also is a little quirky as we are coding our HTML Page into it. We will address this “quirkiness” in a future post when we discuss SPIFFS.

That’s It!

Happy Exploring!

Related Content:
ESP8266 LittleFS Tutorial Series

If you like my post then please consider sharing this. Thanks!

2 responses to “ESP8266 NodeMCU Web Server: No Page Refresh using AJAX and Javascript”

  1. ESP8266 NodeMCU Web Server – Control components from mobile phone

    […] refreshing and you are beind redirected to a new url. To know how to fix this then read the next article on how we can use AJAX and Javascript so that no page refresh is […]

  2. h.ch Avatar
    h.ch

    Hello!

    Thank you for this project! I am very new to ESP8266 and webservers and how it all works, so your project was a great help for me. However, I came upon a problem and wanted to know your opinion on it:
    When I now toggle the checkbox, I receive the request and noticed in the terminal, that the connection point increases every time I toggle it. When it reaches the max. connection (0-4), it doesn’t receive any requests anymore.
    Do you know how I could

Leave a Reply

Your email address will not be published. Required fields are marked *