Categories
Programming

Javascript load more plugin6 min read

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

  1. load – A function to load data from the JSON API page using ajax.
  2. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *