Filter With Pagination in JavaScript

In this project, we will use REST Countries API to fetch data.

We will learn to:

  • fetch data from API
  • paginate data
  • filter data based on select option

HTML

<div class="container">
  <select name="select" id="select">
    <option value="All">All</option>
    <option value="Africa">Africa</option>
    <option value="Asia">Asia</option>
    <option value="Europe">Europe</option>
    <option value="Oceania">Oceania</option>
    <option value="North America">North America</option>
    <option value="South America">South America</option>
  </select>
  <div class="countries_wrapper"></div>
  <div class="pagination">
    <ul></ul>
  </div>
</div>

CSS

html {
    box-sizing: border-box;
}
*,
*::before,
*::after {
    box-sizing: inherit;
}
body {
    padding: 0;
    margin: 0;
    height: 100vh;
    background-color: #48014B;
    display: flex;
    justify-content: center;
}
.container {
    width: 80%;
    margin-top: 50px;
}
.countries_wrapper {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}
.country_detail {
    display: flex;
    flex-direction: column;
}
.country {
    padding: 5px;
    text-align: center;
    font-family: Arial, Helvetica, sans-serif;
    color: #fff;
    background-color: #FC255A;
    border-top: 2px solid #000;
}
h2,
p {
    margin: 0;
    padding: 0;
}
ul {
    margin-top: 50px;
    padding: 0;
}
li {
    display: inline-block;
    padding: 12px;
    color: #ddd;
    background-color: #FC255A;
    border: 1px solid #000;
    cursor: pointer;
}
i {
    padding: 5px;
    color: #fff;
}
.current {
    background-color: #fff;
    color: #FC255A;
}

#select {
    margin-bottom: 15px;
    padding: 9px;
    font-size: 1.2rem;
    border: none;
    outline: none;
}

JS

let list = [];
let postPerPage = 6;

const countries = document.querySelector('.countries_wrapper');
const pagination = document.querySelector('.pagination');
const selectValue = document.querySelector('#select');

function getCountries() {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://restcountries.com/v3.1/all');

    xhr.onreadystatechange = function () {
        if (this.readyState === 4) {
            if (this.status === 200) {
                list = JSON.parse(this.response);
                loadCountries(1);
            }
        }
    };
    xhr.send();
}

function loadCountries(page) {
    countries.innerHTML = '';
    let startPost = (page - 1) * postPerPage;
    let endPost = page * postPerPage;
    let currentPage = list.slice(startPost, endPost)
    currentPage.forEach(element => {
        let mainDiv = document.createElement('div');
        mainDiv.classList.add('country_detail');
        let detailDiv = document.createElement('div');
        detailDiv.classList.add('country');
        let header2 = document.createElement('h2');
        let p = document.createElement('p');
        let img = document.createElement("img");
        img.setAttribute("src", element.flags.png);
        header2.innerHTML = element.name.common;
        if (element.capital) {
            p.innerHTML = `Captial: ${element.capital[0]}`;
        }
        mainDiv.append(img);
        detailDiv.append(header2)
        detailDiv.append(p);
        mainDiv.append(detailDiv)
        countries.append(mainDiv)
    })
    data.init(Math.ceil(list.length / postPerPage));
}

let data = {
    ul: document.querySelector('ul'),
    list: "",
    page: 1,
    step: 3,
    add(x, y) {
        console.log('x', x, 'y', y)
        for (let i = x; i < y; i++) {
            data.list += '<li>' + i + '</li>';
        }
    },
    first() {
        data.list += '<li>1</li><i>...</i>';
    },
    last() {
        data.list += '<i>...</i><li>' + data.size + '</li>';
    },
    click() {
        data.page = +this.innerHTML;
        loadCountries(data.page);
        data.start();
    },
    paginationLi() {
        let li = pagination.getElementsByTagName('li');
        for (var num = 0; num < li.length; num++) {
            if (+li[num].innerHTML === data.page)
                li[num].className = 'current';
            li[num].addEventListener('click', data.click, false);
        }
    },
    finish() {
        data.ul.innerHTML = data.list;
        data.list = "";
        data.paginationLi();
    },
    start() {
        console.log(data.size)
        if (data.size < postPerPage) {
            data.add(1, (data.size + 1));
        }
        else if (data.page < data.step * 2 + 1) {
            data.add(1, data.step * 2 + 4);
        }
        else if (data.page > data.size - data.step * 2) {
            data.first();
            data.add(data.size - data.step - 3,
                data.size + 1);
        }
        else {
            data.first();
            data.add(data.page - data.step + 1,
                data.page + data.step);
            data.last();
        }
        data.finish();
    },
    init(paginationData) {
        data.size = paginationData;
        data.start();
    }

}

async function fetchRegion(region) {
    const response = await fetch(`https://restcountries.com/v3.1/region/${region}`);
    const data = await response.json();
    console.log(data);
    list = data;
    loadCountries(1);
}

selectValue.addEventListener('change', function () {
    if (this.value === "All") {
        getCountries()
    } else {
        fetchRegion(this.value);
    }

})
function init() {
    selectValue.value = "All";
    getCountries()
}

document.addEventListener('DOMContentLoaded', init);