EMMA GEORGE
EMMA GEORGE
HomeAboutProjectsResume

Search the Met

Cover Image for Search the Met
Languages used
  • JavaScript
  • HTML
  • CSS
Tools used
  • Met API
  • Bootstrap
View Live DemoGithub Repository
Overview

For this assignment, I used data from The Metropolitan Museum of Art Collection API.

The site allows users to search objects in the museum by department, keyword, and whether or not the object is on display.

Goal

To create a web page that retrieves and displays data from an existing Web API using fetch requests, based on user's input.

Build

I wrote the following search function to fetch results from the Met museum API based on the user's input.

/**
 * Search by department and keyword, optionally only show objects on display
 * @returns data (total, objectIds)
 */
async function search() {
  const queryInput = document.querySelector("#query-input");
  const departmentSelect = document.querySelector("#department-select");
  if (queryInput.value !== "") {
    objectsLoading();
    document.querySelector("#invalid-search").classList.remove("alert", "alert-danger");
    document.querySelector("#invalid-search").innerHTML = "";
    let param = queryInput.value;

    const onDisplayCheck = document.querySelector("#on-display-check");

    // In theory, this search should return only results with images
    // There seem to be some bugs with the API regarding search results. (https://github.com/metmuseum/openaccess/issues/38)
    let url = `https://collectionapi.metmuseum.org/public/collection/v1/search?hasImages=true&`;

    if (departmentSelect.value !== "") {
      url += `departmentId=${departmentSelect.value}&`;
    }

    if (onDisplayCheck.checked) {
      url += `isOnView=true&q=${param}`;
    } else {
      url += `q=${param}`;
    }

    let response = await fetch(url, myHeaders);
    data = await response.json();
  } else if (queryInput.value == "") {
    document.querySelector("#invalid-search").classList.add("alert", "alert-danger");
    document.querySelector("#invalid-search").innerHTML = "You must type in a keyword to search.";
    return;
  }

  // store current data
  currentData = data;
  // create pages based on number of objects returned
  createPages(data.total);

  // display objects, starting from 0.
  displayObjects(1, data.total, data.objectIDs);
}

I wrote a function to create a display card for each museum piece.

function createObjectCard(objectID, objectData) {
  return (
    `<div class="col">
            <div class="card text-center h-100">
                <img src=${objectData.primaryImageSmall !== ""
      ? objectData.primaryImageSmall
      : "img/copyrighted.png"
    } class="card-img-top prev-img" alt="..." onerror="handleBrokenImage(event)">
      <div class="card-body">
        <h5 class="card-title" id="object-title">${objectData.title}</h5>
        <h6 class="card-subtitle mb-2 text-muted">${objectData.objectName}</h6>
        <p class="card-text">
          <ul class="list-group list-group-flush">
             ${objectData.artistRole !== "" ? '<li class="list-group-item"><strong>' + objectData.artistRole + '</strong>: ' + objectData.artistDisplayName + '</li>' : ''}
            <li class="list-group-item"><strong>Department:</strong> ${objectData.department}</li>
            <li class="list-group-item">
              ${!objectData.isPublicDomain ? `<span class="badge rounded-pill text-bg-warning">Copyright Restrictions</span>` : `<span class="badge rounded-pill text-bg-info">Open Access</span>`}
              ${objectData.GalleryNumber !== "" ? `<span class="badge rounded-pill text-bg-success">Gallery ${objectData.GalleryNumber}</span>` : ""}
            </li>
          </ul>
        </p>
        <button type="button" class="btn btn-primary" data-bs-toggle="modal"
          data-bs-target="#detailModal" data-bs-whatever="${objectID}">
          Learn More
        </button>
      </div>
      <div class="card-footer">
        ${objectData.tags ? createTags(objectData.tags) : ''}
      </div>
    </div>
  </div>`);
}

I noticed that there were instances where the API returned broken or blank image links in the response, so I created a function for handling these errors.

/**
 * Replace broken image links from API with placeholder.
 * @param {*} event 
 */
function handleBrokenImage(event) {
  event.target.src = 'img/placeholder.png';
  event.target.onerror = null;
}
Deployment

This web app is deployed with Github pages. You can visit it here.