So I have a javascript/html program below that allows users to enter an item in a textbox and add the item to a checklist that appears under the textbox. They can also remove, highlight, and sort existing items. No duplicate items are allowed to be added.
The application itself works fine but I'm tasked with transferring this program to an HTTP server that handles requests using XMLHttpRequest. The code I'm struggling with is the todo-server.js file.
Task:
I'm struggling with a task where I'm supposed to modify the Add Item button click handler so that the new item name is added to the server’s to-do list data. To do this, my client Javascript will have to make an asynchronous request to the server and include the item data inside the request body, and this is to be done using a POST request. I'm basically using a GET /list request to retrieve the list data and a POST /list request to create a new item within that list data. I think I did the GET /list request correctly, but the POST /list request does not seem to be working.
After the Add button is pressed, I'm not supposed to add the new item to the client’s page until it confirms the request was successful. My approach to doing this was to use the status code in the response from the server where if there is an error that prevents the item from being added, I display an alert that says "Try again!" to the user so that they know to retry their request. I don't know if I'm putting the alert in the correct place and would appreciate some input on this.
Testing:
I was told that to test this functionality, I'm supposed to load the to-do list page in my browser, add a new item, and then refresh the page. Since the client initializes the page by requesting the list data
from the server, any new items should persist after the refresh instead of the list resetting to its original state every time the page loaded. I tested this out and my items never save whenever I refresh the page, so I assume there's something wrong with my POST request.
I would appreciate some guidance or a push in the right direction for getting this to work properly!
To test the server, I run node todo-server.js in cmd and then open my chrome browser and type localhost:3000 in the address bar.
todo.js
let highlightColor = "yellow";
//The array to store all items in the list
let items = []
function init(){
//Initialize the event handlers
document.getElementById("additem").addEventListener("click", addItem);
document.getElementById("removeitem").addEventListener("click", removeItem);
document.getElementById("highlight").addEventListener("click", highlightItems);
document.getElementById("sort").addEventListener("click", sortItems);
renderList(); //call function to fill in the list div
}
//Returns true if an item with that name exists
function isDuplicate(itemName){
for(let i = 0; i < items.length; i++){
if(items[i].name === itemName){
return true;
}
}
return false;
}
function addItem(){
//Verify an item name was entered
let itemName = document.getElementById("itemname").value;
if(itemName.length == 0){
alert("You must enter an item name.");
return;
}
//If it is not a duplicate
if(!isDuplicate(itemName)){
//Add a new object to the items array and render
items.push({name: itemName, light: false, checked: false});
renderList();
}else{
alert("Duplicate item names not allowed.");
}
}
//Removes selected items
//Strategy is actually to build a new array of items to keep
//Then re-assign the items array to this new array
function removeItem(){
let newItems = [];
items.forEach(elem =>{
//If an item isn't checked, we want to keep it
if(!elem.checked){
newItems.push(elem);
}
});
items = newItems;
renderList();
}
//Toggles highlight of selected items
function highlightItems(){
items.forEach(elem =>{
//If the item is checked, toggle its light property
if(elem.checked){
elem.light = !elem.light;
}
});
renderList();
}
//Sort the array, render the list again
function sortItems(){
items.sort(function(a,b){
if(a.name < b.name){
return -1;
}else if(a.name > b.name){
return 1;
}else{
return 0;
}
})
renderList();
}
function toggleCheck(){
//'this' refers to the calling object
//In this case, the checkbox that was clicked
//We saved the 'value' property with the item name
let itemName = this.value;
items.forEach(elem => {
if(elem.name === itemName){
elem.checked = !elem.checked;
renderList();
return;
}
});
}
//Creates new items list HTML and replaces the old HTML
function renderList(){
let highlightColor = "yellow";
//Create a new div to hold the list
//This will replace the old one
let newList = document.createElement("div");
newList.id = "list";
//For each item in the array of items
items.forEach(elem => {
//Create a new div to be child of 'list' div
//Set highlighting based on property of item
let newDiv = document.createElement("div");
if(elem.light){
newDiv.style.backgroundColor = highlightColor
}
//Create and add the new checkbox
let newItem = document.createElement("input");
newItem.type = "checkbox";
newItem.value = elem.name;
newItem.id = elem.name;
newItem.checked = elem.checked
newItem.onclick = toggleCheck;
newDiv.appendChild(newItem);
//Create and add the new text node (the item name)
let text = document.createTextNode(elem.name);
newDiv.appendChild(text);
//Add newly created div to children of list div
newList.appendChild(newDiv);
});
let origList = document.getElementById("list");
origList.parentNode.replaceChild(newList, origList);
}
todo.html
<html>
<head><title>To-Do List</title></head>
<body onload="init()">
<div>Item Name: <input type="text" id="itemname" /> <button type="button" id="additem">Add Item</button></div><br/>
<div id="list"></div>
<div>
<button type="button" id="removeitem">Remove Selected</button>
<button type="button" id="highlight">Highlight/Unhighlight</button>
<button type="button" id="sort">Sort Items</button>
</div>
<script src="todo.js"></script>
</body>
<html>
todo-server.js:
const http = require('http');
const fs = require("fs");
let items = [
{name: "test"}
]
function send404(response){
response.statusCode = 404;
response.write("Unknown resource.");
response.end();
}
function send500(response){
response.statusCode = 500;
response.write("Server error.");
response.end();
}
const server = http.createServer(function (request, response) {
console.log(request.url);
if(request.method === "GET"){
if(request.url === "/" || request.url === "/todo.html"){
fs.readFile("todo.html", function(err, data){
if(err){
response.statusCode = 500;
response.write("Server error.");
response.end();
return;
}
response.statusCode = 200;
response.setHeader("Content-Type", "text/html");
response.write(data);
response.end();
});
}else if(request.url === "/todo.js"){
fs.readFile("todo.js", function(err, data){
if(err){
response.statusCode = 500;
response.write("Server error.");
response.end();
return;
}
response.statusCode = 200;
response.setHeader("Content-Type", "application/javascript");
response.write(data);
response.end();
});
}else if(request.url === "/list"){
fs.readFile("todo.js", function(err, data) {
if (err) {
response.statusCode = 500;
response.write("Server error.");
response.end();
return;
}
response.statusCode = 200;
response.setHeader("Content-Type", "application/javascript");
response.write(data);
response.end();
});
}else{
response.statusCode = 404;
response.write("Unknwn resource.");
response.end();
}
}else if(request.method === "POST"){
if(request.url === "/list"){
let body = "";
request.on('data', (chunk) => {
body += chunk;
})
request.on('end', () => {
let newItem = JSON.parse(body);
if(newItem.hasOwnProperty("itemname")){
items.push(newItem);
response.statusCode = 201;
response.write(String(newItem.name));
response.end();
return;
}else{
send404(response);
alert("Try again!");
}
})
}else{
send404(response);
alert("Try again!");
}
}
});
server.listen(3000);
console.log('Server running at http://127.0.0.1:3000/');