Create a Picture Competition Website in Express JS, MEVN

AJAX Load More

Load More
Load More

When the competition increases, let’s say 100,000. Fetching all those documents in 1 query will take a lot of time and will slow down the website. So we need to fetch only 10 or 20 in 1 requests and display a button that says “Load More”. Clicking that button will fetch the next 10 or 20 and so on.

If you want to know how to add this functionality separately in your project, you can follow our tutorial “Load more button in Node JS and Mongo DB“.

First, we need to include a line in our “home.ejs”. We are creating a separate file so we can use it in multiple places if we want.

<%- include ("includes/load-more") %>

Then create a file named “load-more.ejs” inside “views/includes” folder. In this file, we will show the load more button only if the user is on the home page. Because later on in this tutorial, we will create a page where we will display only logged-in users’ created competition.

So we need to display the button there too. But we will call a different function on that (will come to this later). Following will be the content of “load-more.ejs”:

<div v-if="typeof isHomePage !== 'undefined' && isHomePage">
	<button type="button" id="btn-loadmore" onclick="getAllCompetitions();" class="btn btn-primary btn-block">
	    Load More
	</button>
</div>

We already have a “getAllCompetitions()” function in our “home.ejs”. We need to make the following changes in that:

function getAllCompetitions() {
	var btnLoadMore = document.getElementById("btn-loadmore");
	if (btnLoadMore != null) {
		btnLoadMore.setAttribute("disabled", "disabled");
		btnLoadMore.innerHTML = "Loading...";
	}

	var formData = new FormData();
    formData.append("accessToken", localStorage.getItem(accessTokenKey));
    formData.append("startFrom", competitionApp.loadMore.startFrom);

	myApp.callAjax(navApp.baseUrl + "/getAllCompetitions", formData, function (response) {
        // convert the JSON string into Javascript object
        var response = JSON.parse(response);
        // console.log(response);

        if (btnLoadMore != null) {
			btnLoadMore.removeAttribute("disabled");
			btnLoadMore.innerHTML = "Load More";
		}

        // if the user is created, then redirect to login
        if (response.status == "success") {

        	response.competitions.forEach(function (competition) {
        		competitionApp.competitions.push(competition);
        		competitionApp.allCompetitions.push(competition);
        	});

        	// Incrementing the offset so you can get next records when that button is clicked
        	competitionApp.loadMore.startFrom = competitionApp.loadMore.startFrom + competitionApp.loadMore.limit;
        } else {
        	swal("Error", response.message, "error");
        }
	});
}

Then in your “competitionApp” object in “footer.ejs”, we need to add this “loadMore” object in it:

var competitionApp = new Vue({
	el: "#competitionApp",
	data: {
		baseUrl: mainURL,
		competitions: [],
		allCompetitions: [],
		loadMore: {
			startFrom: 0,
			limit: 10
		}
	},
	methods: {
		...
	}
});

And finally in our “server.js”, we need to get these values from AJAX and apply the offset on the records from Mongo DB. Search the POST route “/getAllCompetitions” and first add these 2 variables in it:

const startFrom = parseInt(request.fields.startFrom);
var limit = 10;

Then change the query as per the following:

var competitions = await db.collection("competitions")
	.find({})
	.sort({
		"createdAt": -1
	})
	.skip(startFrom)
	.limit(limit)
	.toArray();

Refresh the home page and you will see a load more button. If you have more than 10 competitions, then clicking that button will append the next new 10 at the bottom. And you can keep pressing that button until all the competitions are fetched.