JavaScript iDiallo.com https://cdn.idiallo.com/images/id.png Javascript Tips and tricks - iDiallo.com https://idiallo.com/javascript/ https://idiallo.com/javascript/ How to tell an element is in view using JavaScript. https://idiallo.com/javascript/how-to-detect-element-in-view?src=feed Ibrahim Diallo @dialloibu Recently, I've created a dynamic story where I wanted an event to trigger when an element is in view. The solution was simple, but it's easy to make a mistake and drain your website's performance. Let's break it down into how we can create a flexible function that doesn't freeze the page. Note, modern browsers have a new API that makes this problem trivial, but first let's try to understand the problem and how to solve it. Skip to Modern Solution!

First, how do you know an element is in view? Let's create a function called isElementInView() that returns true or false when we pass an element.

const isElementInView = (element) => {
    return false;
}

Today, all major browsers support the getBoundingClientRect() method. This method returns the position of the element on the page. It includes the properties: left, top, right, bottom, x, y, width, and height. Using these properties and the current windows inner width and height, we can check if the element is in view.

const isElementInView = (el) => {
    if (!el) return false;
    const rect = el.getBoundingClientRect();
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= viewportHeight &&
        rect.right <= viewportWidth
    );
};

When an element is in full view and we call the function isElementInView, it will return true. If it is not in view or only partially in view, the function will return false. Now it's nice that we can identify that an element is in view, this would only work if we call the function constantly. This can be achieved by hooking up this function with the scroll event.

Here is how:

window.addEventListener("scroll", () => {
    const element = document.getElementById("my-element");
    if (isElementInView(element)) {
        doSomething();
    }
});

Every time a user scrolls, even by a fraction of a pixel, the browser will trigger the event. If the element is in view then our function doSomething() will be called. There is a potential problem here. If you only want the function doSomething() to be called once, then we will have to make some modifications. For example, we can add a boolean to track if the function has been called already. Let's make that change.

let hasBeenCalled = false;
window.addEventListener("scroll", () => {
    if (hasBeenCalled) {
        return;
    }
    const element = document.getElementById("my-element");
    if (isElementInView(element)) {
        doSomething();
        hasBeenCalled = true;
    }
});

Now, everytime you scroll we first check if the function has been called before we do any work. Only if it hasn't do we check if the element is in view. After we call our function doSomething() we make sure to set hasBeenCalled to true so the function won't be triggered again. This is a good improvement, but I can't help but think that every time we scroll, we are still triggering an event, even if we don't do a lot of computation with it. Let's try to improve this by clearing the event after it has been triggered.

First, we will define the onScroll function so we can reference it later. When the event is triggered, we will remove the event from the page.

const onScroll = () => {
    const element = document.getElementById("my-element");
    if (!isElementInView(element)) {
        return;
    }
    doSomething();
    window.removeEventListener("scroll", onScroll);
};
window.addEventListener("scroll", onScroll);

Note, I've updated the condition so that if the element is not in view we exit the function with a return. This works great, but I can't help but think about how often the scroll event is triggered. If I slowly scroll the page by 200 pixels, that means I am calling the onScroll at least 200 times. As a consequence I'm also calling document.getElementById 200 times, and then I'm checking the bounding box properties 200 times as well. The more I scroll, the more I call these expensive DOM methods.

One trick we can use is to limit the number of times the function can be called in an interval. This method is called throttling. For example, we can say: only trigger the scroll event once every 200ms. This will drastically reduce the performance hit. We can do so by adding a delay whenever the event is triggered.

let isCheckingScroll = false;
const delay = 200; // milliseconds
const onScroll = () => {
    if (isCheckingScroll) {
        return ;
    }
    isCheckingScroll = true;
    setTimeout(() => {
        isCheckingScroll = false;
    }, delay);
    const element = document.getElementById("my-element");
    if (!isElementInView(element)) {
        return;
    }
    doSomething();
    window.removeEventListener("scroll", onScroll);
};
window.addEventListener("scroll", onScroll);

When the onScroll event is triggered, we check if isCheckingScroll has been set to true already. This prevents any further work. If it hasn't been set, we set isCheckingScroll preventing any further work. Then we create a time out timeout that will reset the value to false in 200 milliseconds in our case. This means, the function will only be called once every 200ms.

We've come a long way from where we started. Now we know how to efficiently trigger an event when an element is in view. But it becomes tedious to rewrite these steps any time we need to monitor an element. Especially when you want to have multiple elements you want to track on the page. So the next step will be to package this into a reusable function. Let's create a function called whenInView(). This function will take an element, a call back function, and rate for how often we want to check during scrolling.

const whenInView = (el, cb, rate = 200) => {
  let isCheckingScroll = false;
  const onScroll = () => {
    if (isCheckingScroll) {
      return;
    }
    isCheckingScroll = true;
    setTimeout(() => {
      isCheckingScroll = false;
    }, rate);
    if (!isElementInView(el)) {
      return;
    }
    window.removeEventListener("scroll", onScroll);
    cb();
  };
  window.addEventListener("scroll", onScroll);
};

Here is an example on how to use it:

const doSomething = () => {
    console.log("Open the box of chocolate");
};

const box = document.querySelector(".box-of-chocolate");
whenInView(box, doSomething, 200);

When the element is in view, we should see the message in the console. You can increase or decrease the rate to something that works best for you.

Other considerations.

One thing to take into account is the whenInView function does not consider if you want to trigger these events multiple times. For example, if the element goes out of view, and then back into view, do we want to trigger it again? I'll leave it as an exercise for the reader.

Also, the isElementInView function only triggers if the element is fully in view. Depending on your needs, you might want to implement a function that considers when the element is partially in view.

const isElementPartiallyInView = (el) => {
    if (!el) return false;
    const rect = el.getBoundingClientRect();
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth;

    return (
        rect.bottom > 0 && // Element's bottom is below the top of the viewport
        rect.right > 0 &&  // Element's right is to the right of the left of the viewport
        rect.top < viewportHeight && // Element's top is above the bottom of the viewport
        rect.left < viewportWidth // Element's left is to the left of the right of the viewport
    );
};

Modern Solution.

Many years back, I had tackled this very issue but there were no solutions provided by the browser. But today, we have an API that takes away all the guess work and let the browser properly calculate when an element is in view saving us precious resources. We can use the IntersectionObserver API. Here is how it works:

const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            doSomething();
            observer.unobserve(entry.target); // Stop observing once in view
        }
    });
}, {
    root: null, // default is the viewport
    rootMargin: '0px', // no extra margin
    threshold: 0.1 // trigger when 10% of the element is visible
});

observer.observe(box);

So the observer observes the element we want to watch and when it is in view it will intersect with the and trigger the call back. Note that we can make use of the threshold parameter to decide how much of the element, in percentage, needs to be visible before we trigger our call back.

We can easily wrap this function as well in our whenInView method and if the browser supports it make use of it:

// Final code
const RATE = 200; // default rate for scrollInView
const scrollInView = (el, cb) => {
  let isCheckingScroll = false;
  const onScroll = () => {
    if (isCheckingScroll) {
      return;
    }
    isCheckingScroll = true;
    setTimeout(() => {
      isCheckingScroll = false;
    }, RATE);
    if (!isElementInView(el)) {
      return;
    }
    window.removeEventListener("scroll", onScroll);
    cb();
  };
  window.addEventListener("scroll", onScroll);
};

const isElementInView = (el) => {
  if (!el) return false;
  const rect = el.getBoundingClientRect();
  const viewportHeight =
    window.innerHeight || document.documentElement.clientHeight;
  const viewportWidth =
    window.innerWidth || document.documentElement.clientWidth;
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= viewportHeight &&
    rect.right <= viewportWidth
  );
};

const observeInView = (element, callback) => {
  const observer = new IntersectionObserver(
    (entries, observer) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          callback();
          observer.unobserve(entry.target); // Stop observing once in view
        }
      });
    },
    {
      root: null, // default is the viewport
      rootMargin: "0px", // no extra margin
      threshold: 0.5, // 50% of the element must be visible
    }
  );

  observer.observe(element);
};

const whenInView = ( () => {
    return "IntersectionObserver" in window
        ? observeInView
        : scrollInView;
})();

// Example usage:
whenInView(document.querySelector('#myElement'), () => {
  console.log('Element is in view!');
});
]]>
Mon, 23 Jun 2025 23:42:50 GMT https://idiallo.com/javascript/how-to-detect-element-in-view?src=feed
Complex function call delays without nesting in JavaScript https://idiallo.com/javascript/delay-callbacks-and-promises?src=feed Ibrahim Diallo @dialloibu I wanted to write a function that allowed me to wait for a specific time to run the code. The quick and dirty way to do it was to use setTimeout and nest callbacks. For example, at the end of an action, I would like to play an animation before I remove the element from the page. Let's see how we can do that with setTimeout.

function victoryDance(element) {
    // start the animation
    element.classList.add("animate");

    // after 2 seconds start the clean up
    setTimeout(() => {

        // stop the animation
        element.classList.remove("animate");

        // fade after 300 ms
        setTimeout(() => {
            // fade the element out
            element.classList.add("fade-out");

            // after 300 ms, remove the element
            setTimeout(() => {
                element.parentNode.removeChild(element);
            }, 300);
        }, 300);
    }, 2000);
}

The code is self-explanatory. victoryDance takes an element, animates it, stops the animation, fades the element out, then removes it from the DOM. As you can see, each action is nested into a setTimeout. The more actions I want to perform, the deeper I'd have to nest my functions. Instead, here is how I would like my code to look like instead.

function victoryDance(element) {
    // start the animation
    element.classList.add("animate");

    Util.wait(2)
    .then( wait => {
        element.classList.remove("animate");
        return wait(.3);        
    })
    .then( wait => {
        element.classList.add("fade-out");
        return wait(.3);
    })
    .then( wait => {
        element.parentNode.removeChild(element);
    });
}

This is much cleaner, and it is easier to read. If I want to add more delays, I can return wait at the end of each callback and add how much time I need to wait before the next action. To use the then() function, all we have to do is create a Promise. Here is the code.

// Nesting it inside util for portability
const Util = (() => {

    const wait = (delay) => {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve(wait);
            }, delay * 1000);
        });
    };
    return {
        wait,
    };
})();

This is a simple function. wait() returns a Promise. Now when the timer times out, your function is called with a new wait promise as an argument that you can use to delay the next function call when it is resolved. Here is a generic way we can call it.

Util.wait(1)
.then(wait => {
    alert(1);
    return wait(2);
})
.then(wait => {
    alert(2);
    return wait(3);
})
.then(wait => {
    alert(3);
    return wait(4);
})
.then(wait => {
    alert(4);
});

When this is executed, alert is called after 1 second, then waits 2 seconds it is called again, then waits 3 seconds and it is called again, etc. This allows you to daisy chain timed actions one after another.

]]>
Fri, 27 Oct 2023 01:23:24 GMT https://idiallo.com/javascript/delay-callbacks-and-promises?src=feed
How to use pushState without breaking the back button https://idiallo.com/javascript/pushstate-the-proper-way?src=feed Ibrahim Diallo @dialloibu I find it very annoying when I use an instant search field and each key I press creates a new state. What this means every single time I hit the back button, it removes a single key from the URL. I have to press the back button a dozen times to get back to the previous page.

The better way to do it is to update the URL and push state after the blur event. It's only when users clicked outside the input field that they are happy with their search result. So we only create one or two entries.

Here how it is done:

searchInput.onblur = function(){
    let val = this.value
    if (val !== "") {
        history.pushState({},"Search entry - "+ val,"?q="+encodeURIComponent(val));
    }
}
]]>
Fri, 25 Sep 2020 07:54:43 GMT https://idiallo.com/javascript/pushstate-the-proper-way?src=feed
How to create DOM elements efficiently with JavaScript https://idiallo.com/javascript/create-dom-elements-faster?src=feed Ibrahim Diallo @dialloibu At some point, every web application needs an overlay. A sort of pop-up that obscures the background and asks the user to perform an action. Here is how you do it.

First you create the HTML, give the overlay an absolute position, and then set the display to none by default. But what if you don’t have access to the HTML? Luckily, JavaScript has a convenient method for that.

document.createElement(elementName);

You can create any element using this method. The challenge starts when you have a complicated nested hierarchy of elements. Here is an example of an overlay:

<div id="overlay">
    <div class="overlay__inner">
        <div class="overlay__box">
            <div class="overlay__hdr">
                <span class="overlay__close-btn">X</span>
                <h3>The Overlay Title</h3>
                <p>The purpose of this overlay</p>
            </div>
            <div class="overlay__content">
                ...
            </div>
        </div>
    </div>
</div>

Recreating this in JavaScript is easy, but not simple. You have to keep track of every element that needs to be nested. Applying the correct attributes is also tedious. Let's see what it looks like.

var overElem = document.createElement("div");
overElem.id = "overlay";
var overInner = document.createElement("div");
overInner.className = "overlay__inner";
var overBox = document.createElement("div");
overBox.className = "overlay__box";
var overHdr = document.createElement("div");
overHdr.className = "overlay__hdr";
var clsBtn = document.createElement("span");
clsBtn.className = "overlay__close-btn";
var title = document.createElement("h3");
title.innerText = "The Overlay Title";
var subtitle = document.createElement("p");
subtitle.innerText = "The purpose of this overlay";

// a long while later

overHdr.appendChild(clsBtn);
overHdr.appendChild(title);
overHdr.appendChild(subtitle);
overBox.appendChild(overHdr);
...

It is a tedious task. Not only you have to define all elements, you have to make sure you append them in the correct order. This can cause bugs that are hard to track. To make the process easier, I created a couple of functions that turn the process into a more manageable tree.

JavaScript Markup Language or jml

I was inspired by the syntax of a popular JavaScript framework called Hyperapp. Here is how I want my code to create DOM elements to look like.

var overlay = ml("div", { id: "overlay"}, 
    ml("div", { class: "overlay__inner"}, 
        ml("div", { class: "overlay__box"}, [
            ml("div", { class: "overlay__hdr"}, [
                ml("span", {
                    class: "overlay__close-btn",
                    onClick: function() {
                        console.log("closing the overlay")
                    },
                }, "X"),
                ml("h3", {}, "The Overlay Title"),
                ml("p", {}, "The purpose of this overlay"),
            ]),
            ml("div", { class: "overlay__content"}, ["more content"]),
        ])
    )
);

document.body.appendChild(overlay);

This elegant style looks similar enough to the resulting HTML and is flexible enough to debug. What we are doing in this code is we call a function ml(a,b,c) that can have 3 arguments.

The first argument is the type of element we want to create. It can be div, h1, span or any valid HTML tag.

The second argument is the list of attributes we want the element to have. Note that we can also use this to attach events to the element. You can have onClick, onMouseover or any valid element event.

Then the third argument can be 3 things. A string, a DOM element, or an array of strings and DOM elements. This third parameter is automatically converted to an element and then appended to the parent. Note that strings are converted to a TextNode. So including HTML in the string automatically converts it to the corresponding HTML entity.

The library

Let's write the code needed to support this functionality:

function ml(tagName, props, nest) {
    var el = document.createElement(tagName);
    if(props) {
        for(var name in props) {
            if(name.indexOf("on") === 0) {
                el.addEventListener(name.substr(2).toLowerCase(), props[name], false)
            } else {
                el.setAttribute(name, props[name]);
            }
        }
    }
    if (!nest) {
        return el;
    }
    return nester(el, nest)
}

function nester(el, n) {
    if (typeof n === "string") {
        var t = document.createTextNode(n);
        el.appendChild(t);
    } else if (n instanceof Array) {
        for(var i = 0; i < n.length; i++) {
            if (typeof n[i] === "string") {
                var t = document.createTextNode(n[i]);
                el.appendChild(t);
            } else if (n[i] instanceof Node){
                el.appendChild(n[i]);
            }
        }
    } else if (n instanceof Node){
        el.appendChild(n)
    }
    return el;
}

The ml() function creates the parent element and sets its attributes and events. The nester() function, reads the third parameter and appropriately creates the child elements. Then the results is appended to the parent.

These two very simple functions make it much easier to deal with DOM elements in JavaScript. Plus you don't have to worry about figuring out which elements is the child of which. The hierarchy is in the design.

]]>
Sun, 16 Feb 2020 07:33:42 GMT https://idiallo.com/javascript/create-dom-elements-faster?src=feed
Uncaught TypeError: Cannot read property of null https://idiallo.com/javascript/uncaught-typeerror-cannot-read-property-of-null?src=feed Ibrahim Diallo @dialloibu TL;DR;
  • You are accessing a property of an object that is null. For example, document.getElementById('stuff') returns null. So adding .value will cause the error.
  • You are trying to access a DOM element before the DOM is ready. Use onload or DOMContentLoaded.
  • Test if an object is valid before accessing its property.

There are a few variations of this error depending on the property you are trying to access. Sometimes instead of null it will say undefined. An example will be:

Uncaught TypeError: Cannot read property 'value' of null

Uncaught TypeError: Cannot read property 'innerHTML' of null

All this means is that you are trying to access a property of an object that is undefined. These usually happens when we don't test an object before using it. Here is a common scenario.

// We want to get the value of an input. 
var inputVal = document.getElementById("input").value;

This will result in Uncaught TypeError: Cannot read property 'value' of null. The reason will be that the element with id input does not exist. Let me break it down in simpler steps;

var input = document.getElementById("input"); 
input // when this fails, it returns null. input = null
var inputVal = input.value;
// this is the same as the following. 
var inputVal = null.value;
// null does not have the property 'value'

When you break it down, the error actually makes sense. To make sure that you don't get this error, you have to make sure that btn, or any object you use, is not null before you use it. For our example:

var input = document.getElementById("btn");
var inputVal = "";
if (input) {
    inputVal = input.value;
}

Sometimes, your object is nested deeper like Tree.folder.path. You just have to make sure that if you need to access folder, than Tree has to be defined. And if you need to access path, then folder needs to be defined.

In some cases, this error is a symptom of another issue. Why would getElementById return null if the element actually exists on the page? Probably because the function is called before the DOM is ready. Always be careful when accessing a DOM element before it is ready.

]]>
Wed, 13 Mar 2019 18:20:39 GMT https://idiallo.com/javascript/uncaught-typeerror-cannot-read-property-of-null?src=feed
Why Use Prototype in JavaScript https://idiallo.com/javascript/why-use-prototypes?src=feed Ibrahim Diallo @dialloibu There is a clear reason why you should use prototypes when creating classes in JavaScript.

They use less memory.

When a method is defined using this.methodName a new copy is created every time a new object is instantiated. Let's look at an example.

In most Object Oriented programming languages a class has a constructor. A constructor is a sort of initializing function that is called every time a new instance of the class is created. Usually the Constructor function name is defined using the actual class name or the keyword constructor:

// In Java
public class Animal {

    private String _name;
    // constructor function
    public Animal(name){
        // this content will be executed when an instance is created:
        // Ex: Animal cat = new Animal('cat');

        _name = name;
    }

}

// In PHP
class Animal {

    private $name;
    public function __constructor($name){
        // this content will be executed when an instance is created:
        // Ex: $dog = new Animal('dog');

        $this->name = $name;
    }

}

But how about in JavaScript? Do we have a constructor? Yes we do, only everything in JavaScript is a weird, so the constructor is the class/function/constructor itself.

// In JavaScript
function Animal(name){
    // this is the class and the constructor at the same time.
    // Ex: var cat = new Animal('cat') 
    this.name = name;
}

So when we call new Animal() the constructor is called immediately. This is where the problem of performance occurs. Imagine I define three functions inside the constructor, this means every single time, those functions are defined anew.

function Animal(){
    this.walk = function(){};
    this.talk = function(){};
    this.jump = function(){};
}

We are creating duplicate functions every single time. If I create two or three objects, then the problem is negligible. But if we create a herd of animals, we start seeing our memory growing because for each animal we are creating a whole new method at run time/instance time.

var cat = new Animal();
var dog = new Animal();
(cat.walk === dog.walk) // false 

The walk of the first object is different then the walk of the second object because each was created during instantiation. In other words, Animal does not know that the method walk() exists before being instantiated.

The solution to the problem is to use Prototypes. What it does is allow us to define the methods once, as a blue print, and have each instance build from it.

function Animal(){};
Animal.prototype.walk = function(){};
Animal.prototype.talk = function(){};
Animal.prototype.jump = function(){};

Now any new instance has a blue print of the class before being created. So every walk is a walk, and every jump is a jump:

var cat = new Animal();
var dog = new Animal();
(cat.walk === dog.walk) // true

Imagine creating a virtual DOM where each DOM element has a few methods. If you use the non-prototypical way with this you will be recreating each method for each virtual DOM element. Shortly after you will notice your application slowing down. But use prototypes and the methods are defined only once thus take much less memory. This is similar to how jQuery defines methods for DOM elements. They don't create a new .css for each element for example, they define it once using a prototype.

The only inconvenience of using prototypes is that there is no easy way to create private methods or variables.

function Animal(){
    // this varialbe is private
    var private_var = 10;

    // this function is public
    this.walk = function(){};

    // this function is private
    function dance(){}
}

How you plan to use a class should be the deciding factor for using prototype or non-prototype methods. If you are going to create a lot of instances, use prototypes.

]]>
Tue, 14 Nov 2017 10:33:08 GMT https://idiallo.com/javascript/why-use-prototypes?src=feed
Optimization: Minimize look-ups in for loops. https://idiallo.com/javascript/minimize-lookups-in-for-loops?src=feed Ibrahim Diallo @dialloibu In JavaScript, like in many other languages a loop can be defined in many ways. The standard of course is the for-loop, the while loop, or do while loop. They are all natively implemented in JavaScript and benefit from the just in time compiler to be optimized for speed. There is recursion too that can be considered a loop, but let's limit ourselves to the native ones.

When I started learning JavaScript, the simplest way to iterate through sets of values was using a for-loop. Here is a simple example of it being used.

// Select elements by class name. This was in 2009 so bear with me
var allElements = document.getElementsByTagName("*");
var elements = new Array();
var className = "selected";

for(var i = 0; i < allElements.length;i++){
    if (allElements[i].className.indexOf(className) != -1 ) {
        elements.push(allElements[i]);
    }
}

console.log(elements); 
// all elements with selected class name.

This worked pretty well. You can wrap it in a function and call it whenever you need to get an element by its class name. However, there are a few things that are redundant.

For each iteration of the loop, we are access a property of the allElements object.

V8 design docs

Most JavaScript engines use a dictionary-like data structure as storage for object properties - each property access requires a dynamic lookup to resolve the property's location in memory. This approach makes accessing properties in JavaScript typically much slower than accessing instance variables in programming languages like Java and Smalltalk.

If I wrote it like this it would be easier to understand: allElements["length"]. When we run our loop, this object property look up happens as many times as the total number of elements. It would be nice if we can do the look up only once and get over it. Well we can.

for (var i = 0, l = allElements.length; i < l; i++)

Now the value of the length property is saved once in a variable l for length, and the condition only has to compares two literals, which is much faster.

Unfortunately, inside our loop there are also other problems. Inside the if statement we are checking if the class name exists, to do so we are using another look up: allElements[i]. And when we meet our condition, we are doing the same look up again to append it to our array. We can fix this in two steps.

First we can save that element in a variable so we don't have to do the look up multiple times.

for (var i = 0, l = allElements.length; i < l; i++) {
    var currentElement = allElements[i];
    if (currentElement.className.indexOf(className) != -1 ) {
        elements.push(currentElement);
    }
}

This is a great improvement and it makes it easier to read. We could call it a day but there is one little thing that isn't quite right. In JavaScript, creating a new variable in a for-loop doesn't add it to a new scope. Instead, the variable is hoisted up to the top of the current scope. For each iteration we are hoisting up a new variable that overwrites the previous one. To fix this, we can declare the variable outside of the loop.

var allElements = document.getElementsByTagName("*"),
    elements = [],
    className = "selected",
    currentElement = null;

for (var i = 0, l = allElements.length; i < l; i++) {
    currentElement = allElements[i];
    if (currentElement.className.indexOf(className) != -1 ) {
        elements.push(currentElement);
    }
}

Note that I also combined the variable declarations. Only one var is used at the top followed by a comma to separate each assignment. Now comes one questions. Optimization or Readability.

We can optimize it some more by moving the second var out of the for-loop since it is going to get hoisted up anyway.

var allElements = document.getElementsByTagName("*"),
    elements = [],
    className = "selected",
    currentElement = null,
    i = 0,
    l = allElements.length;

for (; i < l; i++) {
    currentElement = allElements[i];
    if (currentElement.className.indexOf(className) != -1 ) {
        elements.push(currentElement);
    }
}

But now we get this funky looking for loop: for (; i < l; i++). Although it works just the same and limits the code to do only what it is supposed to do at a slightly faster speed, it might confuse the next developer that has to maintain your code. At points like this, I always choose readability over optimization.


Now that we optimized our loop the question is, was it worth it? How much more speed are we gaining by doing this. The answer is very little. Especially if you are going to run this function only once at a time, the gain is negligible. But, if you are doing something like game programming, or animations, having this sort of mentality will go a long way.

Games usually work using a main loop: A controlled infinite loop that drives the entire game. So in order to obtain the maximum frames per second it's important to make sure your code is not doing anything unnecessary. Removing some extra look ups may help you meet your goals, and hopefully keep the code readable enough so you can always work on it.

]]>
Fri, 28 Oct 2016 00:48:23 GMT https://idiallo.com/javascript/minimize-lookups-in-for-loops?src=feed
Uncaught SyntaxError: Unexpected token https://idiallo.com/javascript/uncaught-syntaxerror-unexpected-token?src=feed Ibrahim Diallo @dialloibu This is a common error in JavaScript, and it is hard to understand at first why it happens. But if you bear with me and remember that Bugs are a good thing you will be on your way in no time.

TL;DR

The JavaScript file you are linking to is returning 404 page. In other words, the browser is expecting JavaScript but it is returning HTML results.

Here is a simple example that may cause this error.

// including jquery.js
// this script is myapp.js

// Get the json data instead of making a request
$(".mybtn").on("click",function(e){
    // Stop the default behaviour.
    e.preventDefault();
    //
    var jsonUrl = this.href + "&json=1";

    $.ajax({
        url: jsonUrl,
        type: "json",
        method: "get",

        success: function(data){
            // do something with the data
            alert(data);
        }
    });

});

In the example above, when the user clicks on a link an ajax request is triggered to return json data. If the json data is returned correctly, everyone is happy and move on. But if it doesn't, well we have to fix it. In situations like this, it's often common to see the error:

Uncaught SyntaxError: Unexpected token <

Don't run to stackoverflow right away. What the interpreter is telling us is that it found a character it was not expecting. Here the interpreter was expecting json, but it received < or HTML. If you check the response on your network developer tab, you will see that the response is HTML.

Another way you can get this error is if you add a script tag and have the src return HTML:

<script src="proxy.php?url=index.html"></script>

All it means is that the interpreter is expecting JavaScript or JSON and you are feeding it HTML/XML. If you don't think you are returning HTML, check if you are not getting a 404.

<!DOCTYPE html>
<html>
...

How do I fix it?

Check the src path to your JavaScript to make sure it is correct. If you are making an Ajax request also check the path. Either the path is incorrect, or the file doesn't exist.

]]>
Wed, 24 Aug 2016 18:20:25 GMT https://idiallo.com/javascript/uncaught-syntaxerror-unexpected-token?src=feed
Magical JavaScript Live Collection https://idiallo.com/javascript/magical-js-html-live-collection?src=feed Ibrahim Diallo @dialloibu JavaScript live collection is a subject that is rarely talked about. Earlier I had written about a caveat when using them. It did help people but one of the problem is that most didn't understand what was happening and thought it was just a quirk in JavaScript.

Let me make things clear. HTML Live collection with JavaScript is not a quirk. It is a feature and you can make good use of it. Let's see how it works.

Remember the DOM APIs document.getElementsBy*? When these methods are used, it is common to use a for loop to go through each element to perform some task. Even though the result of these methods can be treated like Arrays they are not arrays. What they are is an HTML collection. The power and main difference between these and a regular array is that they are directly tied to the DOM. If you update the DOM, the collection is updated accordingly.

Here is one little experience. We are going to create a live collection, and watch it update without any explicit interaction on our part.

var collection = document.getElementsByClassName("collection"); 

Let's say I declare this variable and there are no elements with class name 'collection'. Obviously, this will return an empty array like collection. If I check the length, it will be zero

console.log(collection.length);
> 0

Now let's create an element with said class name and append it to the DOM and see what happens to our collection.

var element = document.createElement("p");
element.className = "collection";
document.body.appendChild(element);

// Checking the length
console.log(collection.length);
> 1

console.log(collection[0]);
> <p class="collection"></p>

The new element found its way into our collection array without having to re-fetch it from the DOM.

This neat little feature can be very useful. You can have a variable that keeps track of, let's say, active users without having to constantly check the DOM or having to pop values in and out of an array.

]]>
Sat, 14 May 2016 03:36:18 GMT https://idiallo.com/javascript/magical-js-html-live-collection?src=feed
Creating a class in JavaScript https://idiallo.com/javascript/creating-a-class-in-js?src=feed Ibrahim Diallo @dialloibu It comes to a surprise that JavaScript, the most popular language on the web, has the most unconventional method for creating a class. In most object oriented programming languages, classes follow a common syntax. Here is one example:

class Person {
    private String fname;
    private String lname;

    public String className = "Person";

    public function __construct(fname,lname){
        this.fname = fname;
        this.lname = lname;
    }

    public function getFullName(){
        return this.fname + " " + this.lname;
    }
}

This is straight forward and coming from any language you will understand what is happening. Except in JavaScript, that's not how you create a class. The word class is a reserved keyword that still haven't found any use in the latest Ecmascript draft.

In JavaScript everything is an object. And that include Functions. And functions are classes...

Ok let me show you. To create a class, you create a function. But this function will be called differently. Let's rewrite our generic class above in JavaScript.

function Person(fname,lname) {

    // private variables
    var firstName = fname,
        lastName  = lname;

    // public variable
    this.className = "Person";

    this.getFullName = function() {
        return firstName + " " + lastName;
    }
}

This looks like a regular function. Using the keyword var we can create private members in the class. And with this, we can create public members. But the main difference occurs on the way we instantiate it.

var person = new Person("Ibrahim","Diallo");
person.getFullName();
> Ibrahim Diallo

When used with the keyword new, like in most languages, we instantiate the class. It may seem confusing at first, but this is just the way it is done in JavaScript, and if you familiarize yourself with it, you will see that it is not so different then other languages.

Note that we can also create Static Classes. It requires no complex naming convention. Let's try to recreate this class as a static one.

var Person = {
    fname: null,
    lname: null,
    className: 'Person',
    getFullName: function() {
        return this.fname + " " + this.lname;
    }
};

One key difference here is that we cannot create private variables. So when trying to decide which type of class you want to create, take this into consideration.

]]>
Sat, 02 Jan 2016 23:39:12 GMT https://idiallo.com/javascript/creating-a-class-in-js?src=feed