When searching the internet for a Javascript load more plugin, I came across a Jquery load more plugin tutorial in this youtube channel – Codecourse.
I highly recommend that the reader watch the Codecourse (formerly PHPacademy) tutorial and subscribe to their channel before continuing.
Link to the tutorial – Load More jQuery Plugin.
The tutorial was a really good and the plugin was very useful. But, with the aim of getting better at javascript and programming in general I tried to customize it.
So I decided to redo it in pure javascript. Here is how it went.
Demo link – Javascript load more plugin demo.
Please refer the above tutorial for creating a server side JSON API. The API would look like this Load more JSON API.
Now let’s get started with our plugin.
How to use?
<script src="lmore.js"</script>
<script>
var itemload=new lmore({elem:cont,source:'json-api-load-more-plugin/',count:3});
</script>
Parameters
- elem: The main container.
- source: JSON API page.
- count: Number of results to load per request.
HTML
The plugin requires an HTML template to work with and the template would look like this.
<div id="cont">
<span class="rescont" >
<div id="ent_cont" class="items" >
<div class="item" >
<p data-field="id" class="hide" ></p>
<h2 data-field="title" ></h2>
<p data-field="description" ></p>
</div>
</div>
</span>
<div id="no_result" class="nores" >No results to display.</div>
<button id="load_more" class="load_more" >Load more</button>
</div>
Elements included are
- #cont – Main Container.
- .rescont – Container where results have to be loaded.
- .items – Container for .item
- .item – Individual data container which would be cloned with each result set.
- [data-field] – The value of this attribute would be matched with the keys in the JSON object and corresponding values would be filled.
- .nores – The element to be shown when there are no results. .rescont would be hidden and .nores would be shown if there are no results.
- .load_more – Button which on click would load more results.
JAVASCRIPT
The plugin would take 3 inputs as given in the usage section.
It would have two main functions
- load – A function to load data from the JSON API page using ajax.
- append – A function to append the loaded data to the DOM.
The plugin
Wrapper
var lmore = function(options) {
this.append = function() {
}
this.load = function() {
}
}
Now we have to set the necessary properties.
//Default options
this.def_option = {
elem: NaN,
source: NaN,
count: 3
};
//set the properties
if (options) {
for (key in options) {
if (this.def_option.hasOwnProperty(key)) {
this[key] = options[key];
}
}
}
//Http request variable
this.http = 0;
//Starting point
this.start = 1;
//Load more button
this.load_more = false;
//Whether it load more button was clicked or not
this.is_load_more = false;
Getting load more button and saving it and it’s display property
//set load more button
if (this.elem.getElementsByClassName('load_more')[0]) {
this.load_more = this.elem.getElementsByClassName('load_more')[0];
this.load_more_display = this.load_more.style.display;
this.load_more.style.display = 'none';
}
Cloning .item element and removing it from the DOM.
//Clone .item and remove it from DOM
this.items = this.elem.getElementsByClassName('items')[0];
this.itemo = this.items.getElementsByClassName('item')[0];
this.item = this.itemo.cloneNode(true);
this.items.removeChild(this.itemo);
this.nores = this.elem.getElementsByClassName('nores')[0];
this.rescont = this.elem.getElementsByClassName('rescont')[0];
this.resdis = this.rescont.style.display;
//function to remove .item from DOM
this.remove = function() {
while (this.items.firstChild) {
this.items.removeChild(this.items.firstChild);
}
}
The load function
this.load = function() {
//Check if load more button was clicked
if (!this.is_load_more) {
this.start = 1;
this.remove();
} else {
this.start += this.count;
}
this.is_load_more = false;
//Abort pending ajax calls if any
if (this.http != 0) {
this.http.abort();
}
//Ajax request
this.http = new XMLHttpRequest();
this.http.onreadystatechange = function() {
if (this.http.readyState == 4 && this.http.status == 200) {
res = JSON.parse(this.http.responseText);
resp = res.items;
//If last result hide load more button else show
if (this.load_more) {
if (!res.last) {
this.load_more.style.display = this.load_more_display;
} else {
this.load_more.style.display = 'none';
}
}
//Check if there are results
//If not the no results text is shown
if (undefined !== resp && resp != null && resp.length) {
//Loop through each result set
//and pass it to append function
for (var i = 0, q = resp.length; i < q; i++) {
this.append(resp[i]);
}
this.nores.style.display = 'none';
this.rescont.style.display = this.resdis;
} else {
this.nores.style.display = 'block';
this.rescont.style.display = 'none';
}
}
}.bind(this);
//.bind is used so that 'this' is set
//to lmore object
//create query string with
//start and count variables
var qs = this.source + '?lmore_start=' + this.start + '&lmore_count=' + this.count;
this.http.open('GET', qs);
this.http.send();
};
The append function
//Append API data to DOM
this.append = function(value) {
//Create a clone of the .item
var clone = this.item.cloneNode(true);
//select all elements in .item
//with data-field attribute
var subs = clone.querySelectorAll('[data-field]');
//loop through API result
for (name in value) {
if (value.hasOwnProperty(name)) {
//loop through elements
//with data-field attr
for (var i = 0, q = subs.length; i < q; i++) {
//id attr = key of object
//set value
if (subs[i].getAttribute('data-field') == name) {
var ptext = value[name];
var text = document.createTextNode(ptext);
this.set_val(subs[i], ptext);
}
}
}
}
//append the cloned element
//to .items
this.items.appendChild(clone);
};
Function to set value of any element
//Function to set value of any element
//params el - element to set value to
//val - the value to be set
this.set_val = function(el, val) {
var node_type = el.nodeName.toLowerCase();
if (node_type != 'input' && node_type != 'select' && node_type != 'textarea') {
el.innerHTML = val;
return true;
}
if (node_type == 'select' || (node_type == 'input' && el.type != 'checkbox') || node_type == 'textarea') {
if (el.hasAttribute('multiple')) {
this.multi_set(el, val);
return true;
}
el.value = val;
return true;
} else if (el.type == 'checkbox') {
el.checked = (val == '1') ? true : false;
return true;
}
return false;
}
//Function to set value of select multiple
this.multi_set = function(sel, values) {
var vals = Array.isArray(values) ? values : String(values).split(',');
var opt;
for (var i = 0, len = sel.options.length; i < len; i++) {
opt = sel.options[i];
opt.selected = false;
for (var x = 0, q = vals.length; x < q; x++) {
if (opt.value == vals[x]) {
opt.selected = true;
}
}
}
}
Initial loading
Also setting event listener on load more button to load data on click
//Load first set of data on page load
this.load('');
//The load more button on click would load
//the nextr set of results
if (this.load_more) {
this.load_more.addEventListener('click', function() {
//is_load_more is set to true
//so that start is not reset
this.is_load_more = true;
this.load();
}.bind(this));
}
And finally the plugin is complete ????.
Download link – lmore.js.
Leave your suggestions below.