How to call a function only for the first time - JavaScript

Viewed 1754

Note: I need to achieve this with pure javascript, I know there is a .one() method in jquery to do this, but I need the same output in pure javascript.

Scenario: I am trying to call a function when a user scrolls and reaches to the 3/4 part or more of the page, but the problem rises when user reaches that part, We all know they can't be pixel perfect so, after the condition is met, the function gets executed per pixel scroll.

I want that to execute only once the condition is met, then add a section at the bottom of the page, and then again user should reach the bottom and the function should get executed only once and so on...

Snippet:

var colors = ['skyblue', 'powderblue', 'lightgreen', 'indigo', 'coral'];

var addPage = function() {
  var page = document.createElement('div');
  page.classList.add('page');
  page.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
  document.body.append(page);
  console.log('added a new page');
}

var scrollAndAdd = function() {
  if (window.scrollY < (window.innerHeight * (3 / 4))) {
    // execute addPage only once for each attempt; it's creating infinite pages
    addPage();
  }
}

window.addEventListener('scroll', scrollAndAdd);
* {
  margin: 0;
  padding: 0;
}

.page {
  height: 100vh;
}
<div class='page' style='background-color: lightgreen'></div>
<div class='page' style='background-color: skyblue'></div>

3 Answers

You don't really need logic to run the function just once; instead, use a different expression to determine whether to add the page. Once the page is added that same expression should no longer evaluate to true until more scrolling is done.

NB: I also changed a bit the random pick logic.

var colors = ['powderblue', 'lightgreen', 'indigo', 'coral', 'skyblue'];

var addPage = function() {
  var page = document.createElement('div');
  page.classList.add('page');
  // Make sure the same color is not selected twice in sequence:
  var colorIndex = Math.floor(Math.random() * (colors.length-1));
  var color = colors.splice(colorIndex,1)[0];
  colors.push(color);
  page.style.backgroundColor = color;
  document.body.append(page);
}

var scrollAndAdd = function() {
  if (window.scrollY > document.body.clientHeight - window.innerHeight - 10) {
    addPage();
  }
}
window.addEventListener('scroll', scrollAndAdd);
* {
  margin: 0;
  padding: 0;
}

.page {
  height: 100vh;
}
<div class='page' style='background-color: lightgreen'></div>
<div class='page' style='background-color: skyblue'></div>

I hope it will help you:

var colors = ['skyblue', 'powderblue', 'lightgreen', 'indigo', 'coral'];

var addPage = function() {
  var page = document.createElement('div');
  page.classList.add('page');
  page.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
  document.body.append(page);
  console.log('added a new page');
}

var scrollAndAdd = function() {
  var a = document.body.clientHeight - window.innerHeight * (5 / 4)
  if (window.scrollY > a) {
    addPage();
  }
}

window.addEventListener('scroll', scrollAndAdd);
* {
  margin: 0;
  padding: 0;
}

.page {
  height: 100vh;
}
<div class='page' style='background-color: lightgreen'></div>
<div class='page' style='background-color: skyblue'></div>

Well how about curry it up with local flag.

var colors = ['skyblue', 'powderblue', 'lightgreen', 'indigo', 'coral'];


const localCurry = function(func, immediateAction) {
  var flag;
  return  function() {
    var context = this, args = arguments;
    var callNow = immediateAction && !flag;
    flag = true;
    if (callNow) func.apply(context, args);
  }
}


var addPage = localCurry(function() {
  var page = document.createElement('div');
  page.classList.add('page');
  page.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
  document.body.append(page);
  console.log('added a new page');
}, true);

var scrollAndAdd = function() {
  var a = document.body.clientHeight - window.innerHeight * (5 / 4)
  if (window.scrollY > a) {
    addPage();
  }
}

window.addEventListener('scroll', scrollAndAdd);

Now you do have option to reset the flag based on timer or custom logic.

Related