Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript AJAX Basics Programming AJAX Programming AJAX Solution

Is there a way to improve the code and apply the DRY principle?

For example, create one function for executing the XMLHttpRequest object, and one callback function for each AJAX task.

I changed the JSON files a bit, to be more standard.

Here's my widget.js file:

const widget = (filename, divID) => {
    let xhr = new XMLHttpRequest();
    xhr.onreadystatechange = () => {
        if (xhr.readyState == 4 && xhr.status == 200) {
            let data = JSON.parse(xhr.responseText);
            let html = "<ul class='bulleted'>";

            data.forEach(element => {html += `<li class='${element.available?"in":"out"}'>${element.name}<li>`});

            html += "</ul>";
            document.getElementById(divID).innerHTML = html;
        }
    };
    xhr.open("GET", filename);
    xhr.send();
}
widget("./data/rooms.json", "roomList")
widget("./data/employees.json", "employeeList")

4 Answers

Tobias Graefe
Tobias Graefe
11,934 Points

Sure! You can create a functions, that takes the keys and classes as input parameter and reuse it in your callback. Same thing for the reauest routine. Than you simply have to pass in the request object and the data path.

Jan Durcak
Jan Durcak
12,662 Points
const newone = new XMLHttpRequest();
newone.onreadystatechange = function() {                                   
     if (newone.readyState === 4){
       const rooms = JSON.parse(newone.responseText);
      const roomList = document.getElementById('roomList');

      let ul = '<ul class="rooms">';
      rooms.forEach( r => {
         ul += `<li class=${r.available ? "full" : "empty"}>${r.room}</li>`;
      });
      ul += '</ul>';
      roomList.innerHTML = ul;
          }
        };

      newone.open('GET', 'data/widget.json');
      newone.send();
Trevor Maltbie
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Trevor Maltbie
Full Stack JavaScript Techdegree Graduate 17,021 Points

If you use the conditional ternary operator you can make this code simpler too.

rooms[i].available ? roomsHTML += '<li class="empty">' : roomsHTML += '<li class="full">'
Andre Hammons
Andre Hammons
9,278 Points

Here's my attempt to apply the DRY principle.

/* ===========================================
              COMMON FUNCTIONS
=========================================== */

function sendRequest(request, method, json) {
  request.open(method, json);
  request.send();
};

function getValueFromBool(obj=null, prop='', trueVal=null, falseVal=null) {
  // Returns value based on boolean property.
  if (obj[prop] === true) {
    return trueVal;
  } else {
    return falseVal;
  };
};


function createList(jsonData=null, liText='', ulClass='', boolData=null) {
  // Create unordered list and assign class.
  const ul = document.createElement('ul')
  ul.className = ulClass;
  // Loop through parsed JSON to create list items.
  for (let obj of jsonData) {
    const li = document.createElement('li')
    li.textContent = obj[liText];
    li.className = getValueFromBool(obj, ...boolData);
    ul.appendChild(li);
  };
  return ul;
};


/* ===========================================
      EMPLOYEE OFFICE STATUS REQUEST
=========================================== */

const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  // Gatekeeper
  if (xhr.readyState !== 4) {
    return;
  };
  const employees = JSON.parse(xhr.responseText);
  // Select appropriate element to insert list.
  const officeStatus = document.getElementById('employeeList');
  // Create the list and append.
  const employeeList = createList(
    jsonData=employees, 
    liText='name', 
    ulClass='bulleted', 
    boolData=['inoffice', 'in', 'out']
  );
  officeStatus.appendChild(employeeList);
};
sendRequest(xhr, 'GET', 'data/employees.json');


/* ===========================================
        MEETING ROOM STATUS REQUEST
=========================================== */

const xhr2 = new XMLHttpRequest();
xhr2.onreadystatechange = () => {
  // Gatekeeper
  if (xhr2.readyState !== 4) {
    return;
  };
  const rooms = JSON.parse(xhr2.responseText);
  // Select appropriate element to insert list.
  const roomStatus = document.getElementById('roomList');
  // Create the list and append.
  const roomList = createList(
    jsonData=rooms,
    liText='room',
    ulClass='rooms',
    boolData=['available', 'empty', 'full']
  );
  roomStatus.appendChild(roomList);
};
sendRequest(xhr2, 'GET', 'data/rooms.json');