Make a function only run once (Javascript) - javascript

So I'm trying to create a function which changes the 0 slot of an array to an input value. However I want this function to only be able to run once. How do I do this, any help is greatly appreciated thanks.
function submitForm() {
$('#inputForm').submit;
if ($("#inputValue").val() != inputException) {
charSetName();
$("#inputValue").val("");
}
$("#inputValue").val("");
}
function charSetName() {
var nameSet = false;
if (nameSet == false) {
nameSet = true;
charDetails[0] = $("#inputValue").val();
document.getElementById("name").innerHTML = "<li id='name''>Name: " + charDetails[0] + "</li>";
}
}

This is an old question but I was brought here because I needed something similar.
To anyone who comes next time, here was what I eventually did:
I simply declared a variable with an initial count of 0.
Then every time my function runs, it auto increases.
The code I want to run once just checks if the count is 1, then it runs. If not, it doesnt.
Like this:
let count = 0;
count === 1 ? doSomething : doNothing
count++
Does it help?

Try this, I have defined isFunctionCalled:Boolean variable for handle it.
var isFunctionCalled = false;
function submitForm() {
$('#inputForm').submit;
if ($("#inputValue").val() != inputException) {
if (!isFunctionCalled) {
charSetName();
}
$("#inputValue").val("");
}
$("#inputValue").val("");
}
function charSetName() {
var nameSet = false;
if (nameSet == false) {
nameSet = true;
charDetails[0] = $("#inputValue").val();
document.getElementById("name").innerHTML = "<li id='name''>Name: " + charDetails[0] + "</li>";
}
isFunctionCalled = true;
}

Mind the executed variable:
var something = (function() {
var executed = false;
return function () {
if (!executed) {
executed = true;
// do something
}
};
})();

There are a lot of ways to do this.
Just a simple way is to set a flag value.
if(flag){
//your code here...
flag = !flag;
}
SO, if the value of the flag is 1 at first it will work. Then as the flag value is changed to 0, then the next time it is called, it will not be invoked, as flag is 0.

Related

How to create a loop in an interval function (the right way)

I have been trying to replicate an example of a rotating text, but I wanted to make it infinite. However, I get it just once and I think it might be related with this logic:
Original link:
https://codepen.io/galefacekillah/pen/jWVdwQ
My first attempt, applying the recursion, was based on one example in the Mozilla docs:
let nIntervId;
function checkIntervalFinish() {
if (!nIntervId) {
nIntervId = setInterval(RotateText, 4000);
}
}
function RotateText() {
var visibleWord = document.getElementsByClassName('visible')[0],
nextWord = visibleWord.nextSibling;
if (nextWord.nodeType == 3) nextWord = nextWord.nextSibling;
if (!(nextWord == null)) {
visibleWord.setAttribute('class', 'hidden');
nextWord.setAttribute('class', 'visible');
} else {
clearInterval(nIntervId);
nIntervId = null;
}
}
checkIntervalFinish();
My second attempt was using a setTimeup. I also tried changing directly the setTimeup for the setInterval, but it didn't work. If I put a console.log, the interval function is executed infinitely, however, not this function. Although this works, it just executes once as well.
var test = function () {
// MY FUNCTION
var intervalID = setInterval(function () {
var visibleWord = document.getElementsByClassName('visible')[0],
nextWord = visibleWord.nextSibling;
if (nextWord.nodeType == 3) nextWord = nextWord.nextSibling;
if (!(nextWord == null)) {
visibleWord.setAttribute('class', 'hidden');
nextWord.setAttribute('class', 'visible');
} else {
clearInterval(intervalID);
}
}, 4000)
// END
setTimeout(test, 100);
};
test();
Can someone explain to me what is it that I am doing wrong? Some why, I think it is related to the null validation.

Pass dynamic params to IIFE

I've got this issue with passing a variable to an IFFE. did some reading, still didn't figure it out. would really appreciate some guidance here.
i have a click event handler function that gets a certain ID from the
DOM when clicked.
i need to pass that ID to an IIFE
that IFFE needs to either add/remove that ID from an array,
depending if it's already there or not.
This is what I got:
Event:
$(document).on('click', 'input[type="checkbox"]', check);
Click Handler:
function check() {
var id = $(this).closest('ul').attr('data-id');
return id;
}
IIFE:
var checkID = (function (val) {
var arr = [];
return function () {
var i = arr.indexOf(val);
if (i === -1) {
arr.push(val);
} else {
arr.splice(i, 1);
}
return arr;
}
})(id);
right now i'm getting the ID, but returning it to nowhere.
in my IIFE, i did pass an id variable, but it's undefined.
so, how do I pass the ID variable im getting from check() to checkID IIFE?
other solutions are also welcome.
Thanks
In your clickHandler
function check() {
var id = $(this).closest('ul').attr('data-id');
checkID(id);
}
and change checkID to
var checkID = (function () {
var arr = [];
return function (val) {
var i = arr.indexOf(val);
if (i === -1) {
arr.push(val);
} else {
arr.splice(i, 1);
}
return arr;
}
})();
I think you need to do things sort of the other way around. Your check function would return a function used by the event handler, but it would also take a callback to be called after the click handler has run, passing your array.
The check function would look like a mash-up of both your functions:
function check(callback){
var arr = [];
return function(){
var id = $(this).closest('ul').attr('data-id');
var i = arr.indexOf(id);
if (i === -1) {
arr.push(id);
} else {
arr.splice(i, 1);
}
callback(arr);
}
}
As you can see, it takes as a parameter a callback function, which will be called on each execution, passing the current array arr. For example, this is my test callback:
function handler(arr){
alert("Array has " + arr.length + " elements");
}
Finally, your event handler would look like this:
$(document).on('click', 'input[type="checkbox"]', check(handler));
Live example: https://jsfiddle.net/src282d6/
Using getter/setter-like functions in your IIFE function makes it much more organized and readable. Then, use these functions to pass, store, and read data across your IIFE function.
var checkID = (function () {
// your array
var arr = [];
// public
return {
// get
getArray: function(){
return arr;
},
// set value
setArray: function(val) {
var i = arr.indexOf(val);
if (i === -1) {
arr.push(val);
} else {
arr.splice(i, 1);
}
}
}
})();
Use it as follows:
checkID.getArray(); // returns default empty array []
checkID.setArray('car1');
checkID.setArray('car2');
checkID.setArray('car3');
checkID.setArray('car4');
checkID.setArray('car4'); // test splice()
checkID.getArray(); // returns ["car1", "car2", "car3"]

How to quit an each() loop and return early from the outer function?

I am trying to return early from an event handler function if a certain condition is met (If the id selected is already in my question list.)
However I am not seeing the results that I expect.
When the condition is met I get the "I should return" message, but I am also getting the "did I still go here?" message. This is still allowing the rest of the code to execute in this function.
my.test.on('click', '.question-tagging .add-question-type', function() {
var questionIds = getSelectedQuestionIds();
console.log("questionIDs = " + questionIds);
var currentQuestions = $.each($('.question-list .question-item'), function () {
console.log("Question ID = " + $(this).find('.remove-tag').data('questionid'));
if (questionIds == $(this).find('.remove-tag').data('questionid'))
{
console.log("I should return");
return;
}
});
console.log("did i still go here?");
// more code...
});
Returning from each(), as you saw, isn't returning from the click handler. You can get what you want if you abandon each() for a simple for loop:
my.test.on('click', '.question-tagging .add-question-type', function() {
var questionIds = getSelectedQuestionIds();
console.log("questionIDs = " + questionIds);
var currentQuestions = $('.question-list .question-item');
for ( var i = 0; i < currentQuestions.length; ++i )
{
var q = $(currentQuestions[i]);
console.log("Question ID = " + q.find('.remove-tag').data('questionid'));
if (questionIds == q.find('.remove-tag').data('questionid'))
{
console.log("I should return");
return;
}
}
console.log("did i still go here?");
// more code...
});
return will only stop execution of the function it's in. In your case, it will stop execution of the loop, but not the outer click handling function. You can use a boolean flag to determine if you should continue with the outer function, like this:
my.test.on('click', '.question-tagging .add-question-type', function() {
var questionIds = getSelectedQuestionIds();
console.log("questionIDs = " + questionIds);
var shouldContinue = true; //set up a flag
var currentQuestions = $.each($('.question-list .question-item'), function () {
console.log("Question ID = " + $(this).find('.remove-tag').data('questionid'));
if (questionIds == $(this).find('.remove-tag').data('questionid'))
{
console.log("I should return");
shouldContinue = false; //flip the flag to false
return;
}
});
if( shouldContinue ) //only continue if condition wasn't met
{
console.log("did i still go here?");
// more code...
}
});
You have to use return false to break out of $.each loop. However, that will only break out of the loop callback and the control will be returned to the click handler function.
If you whish to return early from that function as well you will need another return statement in the click handler.

Check whether function has run fully before, based on variable

I have a function which "types" out a header title as though it is being typed on the screen.
The typer only starts typing once a particular section of my site is "active" or is seen on the screen.
At present, it takes the outputID aka the area where this text will be typed into. There are two instances of this function being run, each with different outputIDs - I only want the function to run once per outputID.
This is how the function is initially called.
<h2 id="typer-get-in-touch" class="typer" data-text="Get in Toche^^^^^ Touch"></h2>
if(anchorLink == 'contact'){
var outputID = $("#typer-get-in-touch");
textTyping(outputID);
}else if(anchorLink == 'expertise'){
var outputID = $("#typer-expertise");
textTyping(outputID);
}
This is the textTyping function
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
var textArray = textString.split("");
var texttypeing = setInterval(
function() {
typeOutText(outputID,textArray);
}, 170);
function typeOutText(outputID,textArray) {
if (textArray[0] == "^"){
outputID.text(function(index, text){
return text.replace(/(\s+)?.$/, '');
});
textArray.shift();
}else {
if (textArray.length > 0) {
outputID.append(textArray.shift());
} else {
clearTimeout(texttypeing);
}
}
}
}
My issue at present is that the function runs multiple types, and continues to type each time the original anchorLink trigger is achieved. The result is that is writes the title many times e.g:
Get In TouchGet In TouchGet In Touch
Each time the section is navigated to, the typing starts again.
How can I run this function only ONCE per outputID? So once the outputID has been used, the function can no longer run for that data?
JSFiddle of non-working example: https://jsfiddle.net/qLez8zeq/
JSFiddle of mplungjan's solution: https://jsfiddle.net/qLez8zeq/1/
Change
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
to
function textTyping(outputID){
var textString = $(outputID).data("text");
if (textString=="") return;
$(outputID).data("text","");
$(outputID).show();
FIDDLE
What you need to do is to bind the event handler for each ID and then unbind it after it's been triggered the first time. Since you're already using jQuery, you can use the "one" method to do exactly this for each outputID:
$( "#typer-get-in-touch" ).one( "click", function() {
textTyping(outputID);
});
I suppose you could store your processed outputIds into an array and then check if the given outputId is present in the array before starting?
Define your array, check for the existence, if not found, do code example:
var processedIds = [];
function textTyping(outputID) {
var foundItem = false;
for (var i = 0; i < processedIds.length; i++)
{
if (processedIds[i] == outputID) {
foundItem = true;
break;
}
}
if (!foundItem) {
//the rest of your code goes here
}
}
You can add some check at the beginning of your function:
var called = {};
function textTyping(outputID) {
if (called[outputID]) {
return;
}
called[outputID] = true;
// your code
}

Not doing anything for the first time running the function in javascript /jquery

The problem is I need to break the function if it is first time running
is there any function available , or I have to do something like the following?
var times = 1
function abc () {
if (times == 1)
break;
else
.....
times++;
}
times = 0;
Thanks.
You can use this pattern:
function abc() {
if (!abc.flag) {
abc.flag = true;
return;
}
// .. rest of the code
}
It's based on the fact that Function is also an object in Javascript.
Basically this is a Memoization pattern. It has disadvantage that the flag property can be overwritten by another code. The advantage is that you don't need to pollute global scope with additional variables.
thg435 proposed much more elegant solution.
It appears to me that you're trying to solve the problem in the wrong place. Can you tell us the whole story?
In the meantime, something like this should do the trick:
function abc() {
abc = function() {
// ...actual work...
}
}
Details depend on how your function is defined (globally, locally, as a method).
var isFirstTime = true;
function abc () {
if (isFirstTime)
{
isFirstTime = false;
return;
}
.....
}
abc(); //returns
abc(); //runs
var firstTime= true
function abc () {
if (firstTime)
{
firstTime = false;
return;
}
else
{
.....
}
}
Try This :
var times = 1;
function abc () {
if (times == 1){}
else{
.....
times == 0;}
}

Categories

Resources