DEV Community

loading...

Build an Unsplash Photo Search App Using Vanilla JavaScript

toluagboola profile image Tolu Agboola ・5 min read

In this article, I will explain how I used JavaScript to build an image search app. It fetches and displays images from Unsplash based on the user's search query. This is one of several personal projects I've built to enable me to gain some practice on all I've been learning.

My Unsplash search app

Setting up the markup and styles

I thought about what I wanted the page to look like and decided on a simple white page (as shown above) with the input and submit button at the top, and the results in a grid formation. You can view the whole code below:

Tackling the JavaScript

I first globally stored references to the form and some other HTML elements that I was going to work with. I would still select others within functions later. I also added a submit event listener to the form.

const form = document.querySelector('.js-form');
form.addEventListener('submit', handleSubmit);
const nextBtn = document.querySelector('.js-next');
const prevBtn = document.querySelector('.js-prev');
let resultStats = document.querySelector('.js-result-stats');
let searchQuery;
Enter fullscreen mode Exit fullscreen mode

Then I defined the callback function handleSubmit in the event listener as shown below:

function handleSubmit(event) {
    event.preventDefault();
    const inputValue = document.querySelector('.js-search-input').value;
    searchQuery = inputValue.trim();
    console.log(searchQuery);
    fetchResults(searchQuery);
}
Enter fullscreen mode Exit fullscreen mode

This function takes an event as its argument and first of all prevents the page from reloading using the preventDefault() method. It then stores the value of the search input in inputValue and removes any whitespace with the trim() method. It stores the trimmed input value in searchQuery and passes it as an argument to the fetchResults function which is being called there. I logged the value of searchQuery to the console to make sure the right value was being passed.

Fetch results from Unsplash

async function searchUnsplash(searchQuery) {
    const endpoint = `https://api.unsplash.com/search/photos?query=${searchQuery}&client_id=YOUR_ACCESS_KEY`;
    const response = await fetch(endpoint);
    if (!response.ok) {
        throw Error(response.statusText);
    }
    const json = await response.json();
    return json;
}

async function fetchResults(searchQuery) {
    try {
        const results = await searchUnsplash(searchQuery);
        console.log(results);
        displayResults(results);
    } catch(err) {
        console.log(err);
        alert('Failed to search Unsplash');
    }
} 
Enter fullscreen mode Exit fullscreen mode

To be able to use Unsplash's API, you have to create a developer account. Only after that do you get your unique API key with which you can access the photos on the site. An AJAX request is made to Unsplash using a URL containing the endpoint and the relevant query parameters. More information on this is provided in the Documentation page on their website.

The function searchUnsplash takes one parameter (searchQuery), which is inserted into the endpoint as the value of the query query parameter. Now, the URL is stored in a variable endpoint which is passed as a parameter to fetch. The fetch() method takes one argument, the path to the resource you want to fetch, which is stored in endpoint in this case. It always returns a Promise. Now, if the response is 200 OK, it is parsed as JSON which is stored in the json variable. The result is logged to the console so as to view the contents of the JSON data.

Both functions above are asynchronous which means that the await keyword can be used to pause the execution of the function until a promise is resolved. This is achieved by placing the async keyword before declaring a function. I used a try...catch block in the fetchResults function. The try block 'tries' to execute the code within it and, should there be an exception or error, the catch block saves the day and responds appropriately with whatever code is written within it. This is a control flow mechanism which prevents the code from crashing if an error occurs while fetching the results.

Display the results on the page

The next thing is to display the results on the page. If you check the JSON data looged to the console, you will find that it contains several properties which have different contents.

Chrome console containing raw JSON data

The results property is an array in which the search results are contained. Each search result is an object and can be accessed using either dot or bracket notation.

function displayResults(json) {
    const searchResults = document.querySelector('.js-search-results');
    searchResults.textContent = '';
    json.results.forEach(result => {
        const url = result.urls.small;
        const unsplashLink = result.links.html;
        const photographer = result.user.name;
        const photographerPage = result.user.links.html;
        searchResults.insertAdjacentHTML(
            'beforeend',
            `<div>
                <a href="${unsplashLink}" target="_blank">
                    <div class="result-item" style="background-image: url(${url});"></div>
                </a>
                <p class="photographer-name">
                    <a href="${photographerPage}" target="_blank" style="color: black; text-decoration: none;">Photo by ${photographer}</a>
                </p>
            </div>`
        );  
    });
    totalResults = json.total;
    resultStats.textContent = `About ${totalResults} results found`;
};
Enter fullscreen mode Exit fullscreen mode

An empty div with a class of search-results was already created in the HTML file. It is then selected in the JS file within a new function called displayResults which takes a JSON object as an argument. The textContent is also set to an empty string to clear all previous results.

JSON Object

Now, the results array is iterated over using the forEach method. Within the callback function, the nested object can be accessed through the result parameter. If you study the above image closely, you will find that each object in the array contains several keys such as links, user, urls. These can be used to access different categories of information on the object in question.

The first lines within the callback function are variables in which the different values needed are stored. They were all accessed using dot notation and include:

  • the image url
  • the link to the image on Unsplash
  • the name of the photographer
  • the link to the photographer's Unsplash profile

Afterwards, each result is inserted into the searchResults element using the insertAdjacentHTML method. This method takes two arguments: the position of the element, and the text to be parsed as HTML. Template literals are used in the second argument because of the parts of the code that will be changing constantly. These are represented by placeholders in the code. The function displayResults is then called in fetchResults.

Each image is set to be the background of its container, and is also a link to its Unsplash page. The name of the photographer, which links to his/her Unsplash profile, is placed right under the image and the result display was styled using CSS Grid.

Show a loading indicator

This is something to be displayed when a search query is being executed to let the user know that the operation is still in progress. I selected a spinner from this website and pasted the HTML and CSS into my code. A referece to the spinner was stored globally in a variable spinner and then the fectchResults function was updated as follows:

const spinner = document.querySelector('.js-spinner');

Enter fullscreen mode Exit fullscreen mode
async function fetchResults(searchQuery) {
    spinner.classList.remove('hidden');
    try {
        const results = await searchUnsplash(searchQuery);
        pagination(results.total_pages);
        console.log(results);
        displayResults(results);
    } catch(err) {
        console.log(err);
        alert('Failed to search Unsplash');
    }
    spinner.classList.add('hidden');
} 
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this tutorial, we have seen how an interactive application can be built using JavaScript. I hope you learnt a lot from it.

I will be writing a continuation to this tutorial very soon, and it will contain how I added other features like pagination and increasing the limit of results shown per page etc.

Also, I'm currently looking for an internship / junior role. Any information on openings will be really appreciated.

Thanks for reading!

Discussion

pic
Editor guide
Collapse
arthureichelberger profile image
Arthur EICHELBERGER

Hi Tolu ! πŸ‘‹πŸ»

This is some great content! Have you considered using the HTML5 template tag inside of the displayResults function rather than pushing HTML through string?

Collapse
toluagboola profile image
Tolu Agboola Author

Hi Arthur,
Thanks a lot! I didn't know about it and I'm currently reading up on it.