Accessing a JavaScript / jQuery Instance only once - javascript

I have a jQuery function which is called on several events (button click, change etc.)
This function is called in the documentReadyFunction and is feeded with start values..
everytime I call this function, parameters will be passed to the function.
My problem is: I don't want to create a new Object each time I call the function, because if I set a variable which decides if a part of the function is beeing executed or not, will be always overwritten..
What do I have to do, to access the first created instance instead of creating always a new one with every function call..
Down below is a simplyfied version of my function.. Maybe you understand my problem better then.
$.fn.doSomething = function(param1) {
var localParam = param1;
var amIcalledMoreThanOnce = parseInt(0, 10);
if (param1 == 1) {
amIcalledMoreThanOnce = amIcalledMoreThanOnce + 1;
if (amIcalledMoreThanOnce == 1) {
$('#run').val(amIcalledMoreThanOnce);
// fill form fields with URL parameters
// This shall be executed only once after getting the URL vals
} else {
// set the localParam to 0 to exit this loop and reach the outter else..
localParam = 0;
$.fn.doSomething(localParam);
}
} else {
$('#run').val(amIcalledMoreThanOnce);
// use the User Input Data not the URL Params
}
};
$.fn.doSomething(1);
$.fn.doSomething(1);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<input type="number" id="run">

you can use this pattern:
var nameOfYourFunction = (function() {
var initializedOnlyOnce = {};
return function() {
//use initializedOnlyOnce here.
}
})();
here what you see is; you create and run a function immediately when the code is run. The outer function immediately returns the inner function and it's assigned to nameOfYourFunction. Then you can use the nameOfYourFunction(); just as any other function. However any varible declared in the outer function will be available to the nameOfYourFunction() and initializedOnlyOnce will never be initialized again.

Related

Compare functions in Javascript

I have an API that takes a function as an input, and then inside the API, the intent is to add the function to an Array if the function is not already added to the Array.
The call to the API is of the form:
myApiHandle.addIfUnique(function(){
myResource.get(myObj);
});
The API is:
myApiHandle.addIfUnique(myFunc) {
if (myArray.indexOf(myFunc) === -1) {
return;
}
// add to array
}
Now this obviously does not work as expected, since each time a new function is being passed in.
My Question is: Is there a way to pass in a function into the myApiHandle.addIfUnique call that will allow me to compare the existing functions in the array with this function that is currently passed in? The comparison should compare the function name and the object, and if both are the same, then not add the function to the array. I want to avoid adding another argument to the addIfUnique call if at all possible.
In other words, is the below possible:
myApiCall.addIfUnique (someFunc) {
}
If so, what is the someFunc. And what would be the logic inside the API to detect if the function already exists in myArray?
The same problem occurs with addEventListener and removeEventListener, where the callback must be identical (in the === sense) for removeEventListener to remove it.
As you've found, obviously if you call addIfUnique like this:
addIfUnique(function() { })
the function passed each time will be a unique object. The solution is to create the function once:
var fn = function() { };
addIfUnique(fn);
addIfUnique(fn);
A related problem occurs when the function being passed in is a method invocation, so I need to bind it:
var x = { val: 42, method: function() { console.log(this.val); } };
I want to pass a bound version of it, so
addIfUnique(x.method.bind(x));
addIfUnique(x.method.bind(x));
But again, each call to x.method.bind(x) will return a separate function. So I need to pre-bind:
var boundMethod = x.method.bind(x);
addIfUnique(boundMethod);
addIfUnique(boundMethod);
First of all, comparing functions is meaningless, even if two functions are literally different, they may be functionally the same.
And for your problem, you can compare whether it's exactly the same object, or you can compare it literally by using toString() function and regExp.
var addIfUnique = (function() {
var arr = [];
return function(func) {
if (~arr.indexOf(func)) return false;
var nameArr = [];
var funcName = func.name;
var funcRegExp = new RegExp('[^\{]+\{(.+)\}$', 'i');
var funcStr = func.toString().match(funcRegExp);
funcStr = funcStr && funcStr[1];
if (!funcStr) return false;
var strArr = arr.map(function(v){
nameArr.push(v.name);
return v.toString().match(funcRegExp)[1];
});
if (~strArr.indexOf(funcStr) && ~nameArr.indexOf(funcName)) return false;
arr.push(func);
};
}());

Updating a 'this' value in a service via a function

I'm quite new to Angular and am trying to understand how everything works. I've been poking around and couldn't find any information on how to do this. So, I've got a service that defines
this.totalCount = 0;
In my controller, my get request retrieves some emails and then executes a function called addMessage for each message it retrieves. The addMessage function is in my service.
The function in my service looks like this:
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
}
Basically, I am trying to increment this.totalCount each time this function is executed so that it will update and then can be displayed in the view. I have it displaying in the view currently, however its number always remains 0.
I've tried the following:
1.
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
this.totalCount++;
}
2.
var count = this.totalcount
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
count++; //and then attempted to display this value in the view but with no luck
}
Any tips would be greatly appreciated.
try this:
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
}
I assume that you're binding the var this way in your controller and your view
Service :
this.totalCount = 0;
this.totalCount++;
Controller :
$scope.totalCount = service.totalCount;
view :
{{totalCount}}
And if you're actually doing it like this, you should face this kind of trouble.
The main problem is that totalCount is a primitive var and doing this.totalCount++ will break the reference. If you want to keep some var you should bind it as a sub-object.
This way :
Service :
this.utils = {};
this.utils.totalCount = 0;
this.utils.totalCount++;
Controller :
//This is the most important part. You bind an object. Then even if you loose the totalCount reference, your object will keep its own reference.
$scope.myServiceUtils = service.utils;
View :
{{myServiceUtils.totalCount}}
Actually in service (it's a matter of taste) i prefer a lot to use the object syntax instead of this (as "this" can be confusing)
This way :
var service = {};
service.utils.totalCount = 0;
service.addItem = function(){
...
}
return service;
Hope that was your issue.
You pass argument to another function which has different scope than your service. It is trick with assigning current object to variable, which is visible from function.
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
that.totalCount++;
}
Should work.
So you assign that variable with current object, which is visible in inner function scope.
In a function addMessage body, this refers to function scope which is new, and there is no compiler error, but messagesList is a null object and totalCount is incremented, but after program leave function, it's not visible in service, because it is in a function scope which isn't assigned to any variable.
To update service variable as it changes in your controller, use $watch.
$scope.$watch(function() {
return messagesService.totalCount;
}, function(new,old){
$scope.totalmessagecount = messagesService.totalCount;
});
First parameter of $watch if function which return observed for change element. Another is standard function to perform operation after update.

How to return variable value from jquery event function?

Can I get value from jquery event function?
I want to get something like this:
function Init() {
var my_variable = $some_object.click(function() {
var my_variable = 'value';
return my_variable // I need to get the variable value from click event
// but I don't know ways to do it
});
console.log(my_variable); // I want to have possibility to use the value here
}
No.
The function that sets the event handler will have finished running before the event handler runs.
No, you can't do that. You can only capture the value in a variable defined outside the scope of your handler:
function Init() {
var my_variable = '';
$some_object.click(function() {
my_variable = 'value';
});
console.log(my_variable); //Prints empty string
$some_object.trigger('click');
console.log(my_variable); //Prints 'value'
}
The answer to your question is No!. You cannot return a value from event handler.
Now next thing which made you curious is how to get some data which comes from the event handler itself. This is where event propagation comes and passing some data along with that.
Checkout below fiddle which shows how data which was created in event handler of button click, is being passed for any custom purpose.
http://jsfiddle.net/kowmwq9j/
Below is simple html and understandable javascript code
<div id='parent'>
<button id='test'>CLick</button>
</div>
var a=document.getElementById('test');
a.addEventListener('click', function(){
var str='sample';
//creating a custom event with name 'build' and passing object as data
var event = new CustomEvent('build', { 'detail': str });
//dispatches the event which invokes the affected listeners
this.dispatchEvent(event);
})
//Listening for 'build' event
document.getElementById('parent').addEventListener('build', getData, true);
function getData(e){
alert(e.detail);
}
Links shared which can help one to understand the concept. dispatchEvent & createCustomEvent .Hope that helps to answer your question!
Added some comments & links which will help those who aren't aware of the functions & behavior used.
If I understand the question maybe you can do something like this...
Variable = 5 is used within 2 functions...each function does something with it's value...
the last function uses the totals of the first 2 functions and again does something.. So the point is that u can access the 2 totals variables and use them in the third function... As long as you set your function variable as global...so don't put VAR in front of it. If you set var in front of it u are saying that your variable is private for that function...
Change the value of the original variable and all the values changes ....
variable = 5; // this is a global variable
source = $('div#een h2'); // put your source here
function Init(){
source.on('click', function(){
Total1 = variable * 2;
console.log(Total1); // It outputs 10
});
};
Init();
function Init2(){
source.on('click', function() {
Total2 = variable * 5;
console.log(Total2); // It outputs 25
});
};
Init2();
function Init3(){
source.on('click', function() {
Total3 = Total1 * Total2; // here we use the 2 Totals...
console.log(Total3); // outputs the Total of both totals... should be 250
});
};
Init3();

Illegal Invocation jQuery HTML5 Audio Play

Background
Basically, this code takes all of the audio tags on the page, and when one finishes it starts the next one in the DOM.
The Issue
When fnPlay is called I receive an Illegal Invocation error.
//THIS CODE FAILS
var lastAudio = null;
$('audio').each(function(index) {
var fnPlay = $(this)[0].play;
if (lastAudio != null) {
lastAudio.bind("ended", function() {
fnPlay();
});
}
lastAudio = $(this);
});
Now I am sure that the rest of the code is fine, because the following worked.
//WORKS GREAT!
var lastAudio = null;
$('audio').each(function(index) {
var lastAudioObj = $(this)[0];
if (lastAudio != null) {
lastAudio.bind("ended", function() {
lastAudioObj.play();
});
}
lastAudio = $(this);
});
Question
Can anybody explain why I couldn't store the play() function inside my variable fnPlay and call fnPlay(), but I could store the object and call the play() function on the object?
This is because of how the context of JavaScript functions work. The context (or this) inside a function is set when it's ran, not when it's set.
When you call lastAudioObj.play();, the play() function is called in the context of lastAudioObj. Inside play(), this is lastAudioObj, so everything works.
When you do fnPlay() however, it has no context. this inside the function will be null (or window). play() doesn't like that, so it throws an exception.
There are a few ways to fix this.
One is to call the function with .call() to manually set the context.
Set the variables like:
var lastAudioObj = $(this)[0];
var fnPlay = lastAudioObj.play;
Then call:
fnPlay.call(lastAudioObj);
You can also use .bind() to set the context when setting the variable.
var lastAudioObj = $(this)[0];
var fnPlay = lastAudioObj.play.bind(lastAudioObj);
Then you can just call it like:
fnPlay();

Proper javascript functions structure

I'm getting data from my firebase
//user balance check
var balanceRef = new Firebase('https://****.firebaseIO.com/arcade/grabbit/'+category+'/'+brand+'/'+gameId+'/'+'activePlayers'+'/'+userId+'/');
Here's the function that gets the data
//check user balance
function checkBalance(){
balanceRef.on('value', function(snapshot) {
if(snapshot.val()=== null){
mLeft=0
} else{
mLeft=snapshot.val().tokensLeft
}
return mLeft
})
}
When the user clicks a button I 1st check their balance
$('#grabbit').click(function() {
//call checkBalance function on click
var myTokensLeft=checkBalance();
});
the problem here is it's returning the function value as NaN or undefined
I've tested repeated, the function does return a value. Why can't It pick up the value on click? Am I doing something wrong with the structure. I'm very new to javascript
balanceRef.on looks like an async function to me, which is why you won't get a return value.
try something like this:
//check user balance
function checkBalance(callback){
balanceRef.on('value', function(snapshot) {
if(snapshot.val()=== null){
mLeft=0
} else{
mLeft=snapshot.val().tokensLeft
}
callback(mLeft);
})
}
$('#grabbit').click(function() {
//call checkBalance function on click
checkBalance(function(myTokensLeft){
// do something with myTokensLeft
});
});
EDIT: more details
the function balanceRef.on does not return your desired data, it only attaches the function function(snapshot)... to the object balanceRef's value event.
When the object balanceRef's value event gets triggered (i.e. data is available), your function function(snapshot)... gets executed, but it's return values goes nowhere, because the javascript parser has already moved on.
try this:
function checkBalance(){
balanceRef.on('value', function(snapshot){
return 'foo';
});
return 'bar';
}
$('#grabbit').click(function(){
console.log(checkBalance());
// this will print 'bar' in your
// in your console, not 'foo'
});
EDIT 2: to avoid callback chaining, one can use a variable that will be common to both functions. (not a very good practice though, since you cannot be sure that the value has been set, when you want it!)
(function(){
// added the closure to avoid myTokensLeft cluttering
// into global variables
var myTokensLeft;
balanceRef.on('value', function(snapshot){
var mLeft;
if (snapshot.val()=== null){
mLeft=0
} else{
mLeft=snapshot.val().tokensLeft
}
myTokensLeft = mLeft;
});
$('#grabbit').click(function(){
// do something with myTokensLeft
});
}());
It seems to me that on your click event you only create another listener to "value" event and gods know how and when that event is triggered and where the function returns your mLeft.
What is happening in your code is that after each click on "#grabit" always new listener is created, but the function inside is not necessarily to be called and if it is called it is called asynchronously which means by the time it is finished you already got "undefined".

Categories

Resources