sub-title

Also check Orama's Quora and Orama's GitHub
I shall not claim to know so much, but only that I learn new things everyday

Friday, 18 March 2022

My Journey with the Migration from JQuery to Vanilla Javascript

As a front-end Javascript library, JQuery is so easy and versatile to use, the reason I have used it all these years for HTML document traversal and manipulation, event handling, animation, Ajax, etc. But even the best dancer leaves the stage at some point. It is time to say bye to JQuery, albeit in a painful way. Life must go on without JQuery. 

A few months ago, I embarked on a tough journey – a journey which I knew would take me long. I am still trekking through the jungles, mountains and wilderness. At the end of the journey, I must have migrated all my frontend JQuery code to Vanilla (pure) Javascript, or some other modern Javascript library such as React. This appears to be the trend among the developer community given the developments in the Javascript space in recent times, so I will not be left behind. 

The advantage I have is that all the JQuery functionalities will still continue to run normally, so it isn’t like I must complete the migration process now. My systems will not break today or tomorrow because of JQuery. I have enough time for the task. 

In this post, I share some of the migration code snippets that I believe may help others. 

I created two global constants, dqs and dqsa, as short names (alias) for document.querySelector and document.querySelectorAll respectively. This makes it easier to make the function calls later for DOM Manipulation, Event Handling, Ajax, etc.

const dqs = (query) => document.querySelector(query);
const dqsa = (query) => document.querySelectorAll(query);


Provided you are well versed with document methods (which includes querySelector and querySelectorAll), and the CSS selectors (query), it would then be easier to migrate the scripts as I show in the rest of this post. I am going to show as many examples (from my working system) as I can by continuously updating the snippet list below.


DOM Manipulation
  //JQuery
  $("#lastActive").text(lastActive);
  $("#idleTime").text(idleTime);
 
  //Vanilla
  dqs("#lastActive").textContent = lastActive;
  dqs("#idleTime").textContent = idleTime;    

DOM Manipulation
  //JQuery
  $("#flashDiv2Message").html(pendingContactRequests + ' - ' + pendingRequisitions);
  $("#numContactRequestsPending").text(numberContactRequestsPending);
  $("#numRequisitionsPending").text(numberRequisitionsPending);
  
  //Vanilla
  dqs("#flashDiv2Message").innerHTML = pendingContactRequests + ' - ' + pendingRequisitions;
  dqs("#numContactRequestsPending").textContent = numberContactRequestsPending;
  dqs("#numRequisitionsPending").textContent = numberRequisitionsPending;  

DOM Manipulation
  //JQuery
  $(".img-zoom-result").css({"display": "block"});
  imageZoom($(this).attr("id"), "imageZoomDiv");
  
  //Vanilla
  dqsa(".img-zoom-result").forEach(el => el.style.display = "block");
  imageZoom(this.id, "imageZoomDiv"); //zoom this image on imageZoomDiv  

Migrating $(document).ready()
  
  //JQuery
  $(document).ready(function() {  
      //do something
  });
//Vanilla document.addEventListener("DOMContentLoaded", (event) => { //do something });

DOM Manipulation and Event Handling
  //JQuery
  $('#recordImage1, #recordImage2, #recordImage3, #recordImage4, #uploadedImage').mouseleave(function() {
      $(".img-zoom-result").css("display", "none");
  });  
  
  //Vanilla  
  dqsa("#recordImage1, #recordImage2, #recordImage3, #recordImage4, #uploadedImage").forEach(el => {
	el.onmouseleave = function(e) {
  		dqsa(".img-zoom-result").forEach(el => el.style.display = "none");
  	}
  });   

Migrating Ajax to Fetch API
Note: Please do not think that I am still using JQuery in the Vanilla version below where you see fetch(`/get_district_by_id?id=${elemId}&whichAction=${whichAction}`.
Rather, I am using backticks -  template literals - for expression interpolation  such as `${varName}`.
  //JQuery
  $.ajax({
      url: '/get_district_by_id',
      data: {
          id: elemId,
          whichAction: whichAction
      },
      dataType: "text",
      type: 'GET',
      success: function(res) {
          try {
              //do something
              }
          }
          catch {alert('Error loading data');} //string is not JSON object
      },
      error: function(xhr, status, error){
          var errorMessage = xhr.status + ': ' + xhr.statusText;
          alert('Error - ' + errorMessage);
      }
  });  
  
  //Vanilla
  fetch(`/get_district_by_id?id=${elemId}&whichAction=${whichAction}`, {
      method: 'GET', // or 'PUT'
      headers: {
          'Content-Type': 'application/json',
          'X-Source-From-Fetch': 'True',
      },
  })
  .then(response => response.json()) //de-serialize/parse json to javascript object, can now access using response["key"] or response.key
  .then(data => {
      try {
          //do something
      } catch (error) {
          alert(`File: ${error.fileName} \n Line No: ${error.lineNumber} \n Message: ${error.message}`);
      } //string is not JSON object
  })
  .catch((error) => {
      console.error('Error:', error);
  });    

Trigger Click
  //JQuery
  $('#sendbutton').trigger('click');
  //Vanilla
  dqs("#sendbutton").click();  

Trigger Mouseenter
Note:
mouseenter doesnt work like click() trigger for good reasons
  
  //JQuery
  $("#loggedInUsers").trigger("mouseenter");
  //Vanilla
  dqs("#loggedInUsers").dispatchEvent(new MouseEvent('mouseover', { 'view': window, 'bubbles': true, 'cancelable': true }));

Hide Spinner
  //JQuery
  $('#spinner').removeClass('fa-spin').parent().css("z-index", -9999999999).hide(0); 
  //Vanilla
  dqs("#spinner").classList.remove("fa-spin");
  dqs("#spinner").parentElement.style.zIndex = "-9999999999";
  dqs("#spinner").parentElement.style.display = "none";

Closest element

  //JQuery 
  $(this).closest(".modal");
  //Vanilla
this.closest(".modal");

To-do
  
  //JQuery
  
  //Vanilla  

To-do
  //JQuery
  
  //Vanilla  

To-do
  //JQuery
  
  //Vanilla  


No comments:

Post a Comment