can someone please explain this bit in my jQuery book? I don't understand the purpose of the variable initalised.
Here is some explanation in the book:
the taskController remembers if it has been initalized in a local variable called initialised.This ensures that regardless of how many times the init method is called, it will only actually initialize the controller once
jQuery code:
tasksController = function() {
var taskPage;
var initialised = false;
return {
init : function(page) {
if (!initialised) {
taskPage = page;
$(taskPage).find('[required="required"]').prev('label').append( '<span>*</span>').children( 'span').addClass('required');
$(taskPage).find('tbody tr:even').addClass('even');
$(taskPage).find('#btnAddTask').click(function(evt) {
evt.preventDefault();
$(taskPage).find('#taskCreation').removeClass('not');
});
$(taskPage).find('tbody tr').click(function(evt) {
$(evt.target).closest('td').siblings().andSelf().toggleClass('rowHighlight');
});
$(taskPage).find('#tblTasks tbody').on('click', '.deleteRow', function(evt) {
evt.preventDefault();
$(evt.target).parents('tr').remove();
});
$(taskPage).find('#saveTask').click(function(evt) {
evt.preventDefault();
if ($(taskPage).find('form').valid()) {
var task = $('form').toObject();
$('#taskRow').tmpl(task).appendTo($(taskPage).find('#tblTasks tbody'));
}
});
initialised = true;
}
}
}
}();
When this controller is initialized, the "initialised" variable is set to false. Upon calling the init function within the controller, the first line in it checks that the "initialised" variable is not true (and it's not, it's false), then executes the remainder of that code block. At the very end of that block, you can see that this variable is set to true.
This means that the next time you run this function, the local variable is going to have a value of true this time, so when you call the init function, it will re-evaluate that statement first. Since this time "initialized" is true, the check for "is the initialised variable not true" will be false, so the code within that block will not execute.
Related
I'm trying to avoid the use of global variables in my code, so I'm trying to use a work around by declaring them inside of $(document).ready and passing them as parameters to functions outside of $(document).ready, updating them, and then returning the updated value from those functions to manipulate the variables inside of $(document).ready.
Another way around this is to use hidden input fields to store variables but I also heard that was bad practice.
I'm wondering if I should just use global variables, do it the way I'm currently doing it, or use hidden input fields?
Below is a brief example of what I'm trying to accomplish. The variable validations is the variable I want to be able to use and update.
$(document).ready(function(){
var validations = [];
$('#inp').keypress(function(e){
if(e.which == 13){
e.preventDefault();
scanValidation(validations, function(valid){
validations = valid;
});
}
});
}):
function scanValidation(valid, cb){
var scanval = $('#inp').val();
if(valid.includes(scanval)){
//display error
}
else{
var validarr = valid.slice();
validarr.push(scanval);
var myData=JSON.stringify({ "name":"user1", "validations":validarr});
//Makes an ajax call to see if the sent array validarr is a valid request
apiCall(myData,'scanValidation',function(decoded) {
if (decoded.Status!="ERROR") {
valid = validarr;
}
else {
//display error
}
return(cb(valid));
});
}
}
Any variables declared within the immediately executed function below will NOT be in the global scope.
(function () {
var someVar = 'someValue';
$(document).ready(function() {
});
})();
Is it bad practice to instantiate variables inside of $(document).ready as opposed to globally declaring them?
No, not at all! Variables should always be declared in the scope they're needed in, nowhere else.
Another way around this is to use hidden input fields to store variables but I also heard that was bad practice.
I've never heard of that, but yes it definitely sounds like a bad practise. That's just the same as a global variable, but a global variable stored in the DOM for some odd reason.
I'm trying to avoid the use of global variables in my code, so I'm trying to use a work around by declaring them inside of $(document).ready and passing them as parameters to functions outside of $(document).ready, updating them, and then returning the updated value from those functions to manipulate the variables inside of $(document).ready.
That, admittedly, is a bit weird.
The easiest way to improve this is to move the function declaration inside the ready handler as well, and just access the variable there directly - with the additional bonus of not having a scanValidation global variable:
$(document).ready(function() {
var validations = [];
function scanValidation() {
var scanval = $('#inp').val();
if (validations.includes(scanval)) {
//display error
} else {
var validarr = validations.slice();
validarr.push(scanval);
var myData = JSON.stringify({"name": "user1", "validations": validarr});
// Makes an ajax call to see if the sent array validarr is a valid request
apiCall(myData, 'scanValidation', function(decoded) {
if (decoded.Status!="ERROR") {
validations = validarr;
} else {
//display error
}
});
}
}
$('#inp').keypress(function(e){
if(e.which == 13){
e.preventDefault();
scanValidation();
}
});
});
If you want to make scanValidation reusable, so that it could be called from other places as well with its own array, I would suggest to create a factory function that creates validators, each of which is a closure over its own array. That way, the array is declared where it belongs, so that the user of the function does not have to store the state for them:
function makeScanValidator(display) { // any other configuration
var validations = [];
// returns closure
return function scanValidation(scanval) { // take it as an argument
if (validations.includes(scanval)) {
display(/* error */);
} else {
var validarr = validations.concat([scanval]);
var myData = JSON.stringify({"name": "user1", "validations": validarr});
apiCall(myData, 'scanValidation', function(decoded) {
if (decoded.Status!="ERROR") {
validations = validarr;
} else {
display(/* error */);
}
});
}
}
$(document).ready(function() {
var validate = makeScanValidator(function display() { … });
$('#inp').keypress(function(e){
if(e.which == 13){
e.preventDefault();
validate(this.value);
}
});
});
I am trying to execute functions on click, Below is click button on HTML,
Insights.init() will execute on page load will give me some data from server, now with click on button, i need to pass variable to month function to filter data, and with click i want to execute all functions inside Insights()
var Insights = function() {
var initCheckColor = function(vari) {
console.log(vari);
}
var testFunction = function(vari) {
console.log('test');
}
return {
init: function() {
initCheckColor();
testFunction();
}
};
}();
jQuery(document).ready(function() {
Insights.init();
});
function month(vari) {
console.log("hoo");
return {
init: function() {
initCheckColor(vari);
testFunction();
}
};
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Month
Now problem is, i can see "hoo" printed on console when i click on link, but i also want to print it with execution of initCheckColor(vari) function, means i want output two times, but i could not output it,
How can i get output two times?
Problem: Is with this code
function month(vari) {
console.log("hoo");
//this block of code
return {
init: function() {
initCheckColor(vari);
testFunction();
}
};
// upto here
}
When you call the month function you are returning a object with a property named init Note: you are just returning a object and not executing the functions within the property. Also other issue is this property is a function which executes two other function, But those functions are not available in the current scope. As they are equal to Private methods for the Insights object.
Solution: Would be to re initialize the object with data just like how you are doing on page load.
I have fixed your code and added comments in the code where the changes were made.
var Insights = function() {
var initCheckColor = function(vari) {
console.log(vari);
}
var testFunction = function(vari) {
console.log('test');
}
return {
init: function(vari) { // have a input parameter during initialization.
initCheckColor(vari);
testFunction();
}
};
}();
jQuery(document).ready(function() {
Insights.init('something'); // I pass in the string "something" now this will be printed by the initCheckColor function.
});
function month(vari) {
console.log("hoo");
Insights.init(vari); // initialize the Insights object by passing in some value.
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Month
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.
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".
I'm trying to create javascript closure that will tell me if the function has already been run:
This is what I have so far:
function do()
{
var isInitialized = function()
{
var init = false;
if (init == false)
{
init = true;
return false;
}
return init;
}
if (!isInitialized())
{
// do stuff
}
}
My function isInitialized always evaluates to true. I'm like 90% sure I'm not setting the internal variable correctly. How do I fix my code?
First of all, you can't use do as your function name as that's a keyword.
Secondly, you can attach properties right to your function so you don't need a closure or anything like this:
function f() {
if(f.initialized)
return;
f.initialized = true;
console.log('Doing things.');
}
f();
f();
That will give you just one "Doing things." in the console.
Demo (run with your JavaScript console open): http://jsfiddle.net/ambiguous/QK27D/
Functions are objects in JavaScript so they can be assigned properties which provides a convenient mechanism for achieving what you want to do:
function doit() {
if (typeof doit.isInitialized === "undefined") {
doit.isInitialized = true;
// do stuff
}
}
Try this:
function fn(){
if (typeof fn.hasrun!='undefined'){return;}
fn.hasrun=true;
// do stuff
}
Every time you call isinitialized, it'll reset all the variables to default, so init will ALWAYS start out false. The values set afterwards are NOT carried over to the next time isInitialiazed is called.
What you want is a 'static' variable, which JS doesn't directly support, but can be simulated as per this answer: Static variables in JavaScript