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.