javascript change name of called function - javascript

Hi all im very new to javascript so please be gentle.
im mixing php with my calls and I have a slight issue.
I need to alter the function name that is called in an onclick event.
<div class=\"span4\" id=\"pass\">
<button class=\"btn btn-block btn-large btn-warning\" id=\"bypass\" disabled onclick=\"pass(); return false;\">
-
</button>
</div>
above is the div with the std call.
before this point some variables are set from another function call and I need to change the above call to "pinpass2() or pinpass3 etc.
function pincheck(id,type,lastid,pin){
document.getElementById('fade').style.display=\"block\";
document.getElementById('calc').style.display=\"block\";
var staffid = id;
document.getElementById('bypass').onclick = function (){\"pinpass\"+staffid();
return false;
};
}
the above is the function that should do it but i can't seem to get it working.
Any help appreciated.
p.s if i include the following into the pincheck function the desired staffid is diaplayed
alert(\"staff id\"+staffid);

document.getElementById('bypass').onclick = pinpass2;
That should work just fine. pinpass2 is already a function, you can assign it to onclick like any other object (yes, functions are objects in Javascript). So just change the onclick when you need it.
If you can't detect changes to the result of staffid(), then you should use a switch instead.
document.getElementById('bypass').onclick = function() {
switch(staffid()) {
case 1: pinpass(); break;
case 2: pinpass2(); break;
default: pinpass3(); break;
}
};
Though most of the time you don't have to do this. Also, I'm not sure if staffid is supposed to be a function or a variable, but it doesn't change anything.
By the way, this way of attaching handlers is quite old. There's a more powerful one:
document.getElementById('bypass').addEventListener('click', pinpass2, false);
With that you can attach more than one function. To remove one:
document.getElementById('bypass').removeEventListener('click', pinpass2, false);

You can change the onclick attribute the same way you'd change any attribute ?
var elem = document.getElementById('bypass');
elem.setAttribute('onclick', 'pinpass' + staffid + '(); return false;');
FIDDLE

In javascript functions are first class so you can literally just assign pincheck to another variable like this.
var pinpass2 = pincheck;
Now you can still call it like this
pinpass(1,2,3,4);

I'm not 100% from your question, but it looks like you are trying to call a different function based on the staffid variable. I.E. if it is 2 you want to call pinpass2().
If this is a global function you can call window[ 'pinpass' + staffid ]() and it will call the function you want (if it exists).
EXAMPLE: if staffid = 2 then window[ 'pinpass' + staffid ]() is eqivalent to window[ 'pinpass2' ]() which is the same as calling pinpass2().
This works because all global vars (including functions) are properties of the window object, and properties can be accessed using a dynamically generated name and square bracket notation.

Related

jQuery accessing updated values from variables on different events

I have a function which copies the values of a group of inputs to another group of inputs if the user clicks a button.
The function works fine but I'm having trouble with the vars I'm using to get the information. I want to use global variables because I want to use the same variables later on but it only works when I wrap those vars inside the function.
I've posted the two scenarios where it's working and not working below. Can anyone explain why I cannot access the correct value at that given time using a global variable?
EDITS: The 3 elements #admin-name, #admin-email and #admin-number are all present in the DOM when the script is called, as I am doing everything with document ready. I understand that when the script first runs these values will be blank because they haven't been filled out by the user yet. What I don't understand is why can't jQuery get the value once it has been filled out and I call the variable on the click function.
Not Working
var contactName = $('#contact-name').val();
var contactEmail = $('#contact-email').val();
var contactNumber = $('#contact-number').val();
$(".step-two .copy-details").on('click', function(){
$('#admin-name').val(contactName);
$('#admin-email').val(contactEmail);
$('#admin-number').val(contactNumber);
});
Working
$(".step-two .copy-details").on('click', function(){
var contactName = $('#contact-name').val();
var contactEmail = $('#contact-email').val();
var contactNumber = $('#contact-number').val();
$('#admin-name').val(contactName);
$('#admin-email').val(contactEmail);
$('#admin-number').val(contactNumber);
});
Man I struggled with this one, this post helped flesh it out for me, jQuery Global Variable. The problem is the variable called in the click function was still getting the original value of 0. To make the variable update when a new value is added you need to declare it and then wrap it in a change function like so:
JS
// declare the variable
var contactName;
// wrap it in a change function so the value updates
$('#contact-name').on('change', function(){
contactName = $('#contact-name').val();
});
// use the variable inside the function and it will show the updated value
$('.step-two').on('click', 'button', function(){
$('#admin-name').val(contactName);
console.log('contactName = ' + contactName);
});

How may I call a method of the same object inside .append()?

generarGrilla() creates an output that has some html buttons.
Each button calls a method that exist in the same object guardarReserva()
When I load the page guardarReserva() is called without clicking any button, because this line console.log("whatever "+this.i); gets printed into the console.
If I do click one of the buttons that have the listeners, nothing happens.
var reservasAPP = {
i:0,
nombre: function () {
return $('#h09').val();
},
guardarReserva:function(){
var reservaConfirmada = $('#horario'+this.i).html('--> '+this.nombre());
console.log("whatever "+this.i);
return false;
},
generarGrilla: function(){
//it loads from html using jQuery(document).ready();
for(this.i=1; this.i<13; this.i++){
var impresionGrilla = $('#grilla').append("<button class=\"btn btn-primary btn-xs\" onclick=\"return "+this.guardarReserva()+"\">Reservar</button>");
};
},
}
You're actually running guardarReserva() within your .append() function. That is why you see the immediate console.log("whatever "+this.i); when you first open the browser.
I think you want the onclick of that button to call that function. For that (assuming reservasAPP is in the window namespace) you can do something like this:
var reservasAPP = {
i:0,
nombre: function () {
return $('#h09').val();
},
guardarReserva:function(){
var reservaConfirmada = $('#horario'+this.i).html('--> '+this.nombre());
console.log("whatever "+this.i);
return false;
},
generarGrilla: function(){
//it loads from html using jQuery(document).ready();
for(this.i=1; this.i<13; this.i++){
// ---Change is here ------------------------------------------------------------------------|
// V
var impresionGrilla = $('#grilla').append("<button class=\"btn btn-primary btn-xs\" onclick=\"return reservasAPP.guardarReserva();\">Reservar</button>");
};
},
}
Why I couldn't use "this" and I need to use "reservasAPP"
So, let's look at some of your original code (I'll slightly modify it so it is a bit shorter) and see why it wasn't working.
The line where the good stuff happens is within generarGrilla, within the for loop where you call the .append() function.
var i_g = $('#grilla').append('<button onclick="return ' + this.guardarReserva() + '">Reservar</button>');
Now you are correct in the idea that when that line of code executes, the this keyword is pointing at the reservasAPP object. However, what you are doing is not setting the onclick event for the button to run this.guardarReserva(), you are immediately running the this.guardarReserva() function.
Let's look at a small, semi-related example:
var n = function() {
return 'John';
};
var str = 'Hello, ' + n();
Now, what is the value of our variable str? Well, we are doing two things:
First, we have a string literal Hello, .
We are then concatenating it using the + operator with what the function n() returns.
Notice how we are going to use what n() returns rather than the literal 'n()' (string or function). This is because we are actually calling the n() function.
So, at the end of the day:
// str = 'Hello, John';
So, let's go back and look at your original code. What is actually going on there? Well, you are selecting all elements with id set to grilla (I'm assuming there is only one of those) then calling the jQuery append() function. .append() can accept a string as its argument, and it'll take that string, and insert it into the DOM as HTML.
Your string is concatenating three different things.
'<button onclick="return '
The return value of this.guardarReserva()
'">Reservar</button>'
Your guardarReserva function at the end returns false, which when concatenated with a string, uses its .toString() method, which in this case returns the actual word 'false'.
So, if you'd look at your HTML from before, you'd see your HTML code looked like:
<div id="grilla">
<button onclick="return false">Reservar</button>
</div>
Which is not at all what you wanted.
Instead, to fix that issue, I had you pass in one long string (which includes the function name you do want to call). So, your HTML ended up looking like:
<div id="grilla">
<button onclick="return reservasAPP.guardarReserva()">Reservar</button>
</div>
OK, so that's why the function was running right away, and why your button wasn't working. So we need to pass in the function as a string for the HTML button to know to run that function when it is clicked.
So, why can't you pass in the string:
'<button onclick="return this.guardarReserva()">Reservar</button>'
It has to do with how the browser evaluates the this keyword within that button.
In fact, let's do an experiment
<button onclick="console.log(this);">CLICK ME</button>
What happens when I click the button? You can do this experiment yourself. You'll see that it actually logs the literal button. Because within the buttons inline onclick, this refers to the button itself!
You can doubly verify this with this code:
<button id="button-1" onclick="console.log(this.id);">CLICK ME</button>
And see that it logs the string "button-1" (aka, the button's id).
So, if this refers to the button, we can't leave that context to get at our reservasAPP object! By referencing the reservasAPP object directly (assuming it was declared in your main <script></script> tag, thus placing it in the accessible window object), we can access that object, and thus its inner properties.
SIDE NOTE:
I would use a different method altogether for attaching our onclick handler.
I'd use jQuery's .on() function. Here is an example of how you could define generarGrilla:
generarGrilla: function() {
for (this.i = 1; this.i < 13; this.i++) {
// Save our `this` object for later
var self = this;
var button = $('<button class="btn btn-primary btn-xs">Reservar</button>');
// Set the `onclick` handler for our button (that isn't in the DOM yet)
button.on('click', function(event) {
// Use our saved `self` variable, which points to `reservasAPP`
return self.guardarReserva();
});
// `onclick` is set, insert our button into the DOM
var impresionGrilla = $('#grilla').append(button);
};
}
Now, when you run reservasAPP.generarGrilla();, it'll insert your buttons, and they'll all have onclick event handlers.
You can read this post on why'd some people think it's better to use attached event handlers vs inline JS on HTML attributes.
Have you tried reservasAPP.guardarReserva() instead of this.guardarReserva() ?

dynamically generated js buttons with closures to assign onclick function parameters

I am running into a problem people have posted before: JavaScript dynamic parameters
But my code uses nodes rather than innerHTML assignments, so the existing SO post doesn't seem to apply to my code.
I want to dynamically generate HTML buttons in a table. For each button, I want to call a function with parameters that depend on the button's index/position in the table. First I tried just using lambda functions with the variable over which I was incrementing. This didn't work, so I also tried dynamically named variables, meaning each button should be passing a differently named variable to deal with lazy-loading effects. But this didn't work either. You can see both versions of what I tried in the code below:
This code I paste below is in a for-loop. In the following, I increase i by 1 each time. offset and jj are unchanged within the loop.
var variableDynamic = i.toString();
window['variableName' + variableDynamic] = i + offset;
upvote.onclick = function() {
upVoteA(i + offset, jj);
//upVoteA(window['variableName' + variableDynamic] , jj);
};
upvote.innerHTML = "Upvote"
Someone told me to look into closures, so following this recommendation: http://www.usepatterns.com/blog/javascript-closures I rewrote the onclick function declaration as:
upvote.onclick = function() {
var a = i + offset;
var b = kk;
function closeIt(){
upVoteA(a,b);
}
closeIt();
};
This still has the same effect that every button calls upVoteA with the same parameter, namely the last/highest value.
I realize I could refactor my code to turn these into .innerHTML set statements and then I'd print the variable and it would be set as a printed statement instead of a lazily-loaded variable. But I'd like not to do that if possible. (apologies that it's not technically lazy loading, the name seems reasonably apt)
Is there a way to make my code work? And why are the closures failing? I thought closures should preserve the environment they were created in, but that is not the case with my code. Which portion of the "environment" are preserved with closures?
This is a very bad answer, but it works
var funcStr = "function dummy() { upVoteA(" + (i + offset) + "," + jj + "); }";
eval(funcStr);
upvote.onclick = dummy;
But if you have something better, please let me know.

Passing selectors as function parameters in jQuery [duplicate]

This question already has answers here:
Calling an event handler with an argument [duplicate]
(5 answers)
Closed 8 years ago.
Fiddle Example
Can I pass selectors other than $(this) selector as function parameters?
What I mean is that the selectors (#Aarea and Barea) I want to pass are the ones that I want to append some HTML content to.
function info(a){
var source = $(this).data('source')
$(a).html(source)
console.log(source);
}
$('#one').click(info('#Aarea'))
$('#two').click(info('#Barea'))
<button data-source="AAA" id='one'>Button</button>
<div id="Aarea"></div>
<div id='Barea'></div>
<a href='#' data-source='BBB' id='two'>Click</a>
But it doesn't work unless I don't use the parameters and specify those selectors in the function.
What your code:
$('#one').click(info('#Aarea'))
...is doing is calling info and passing its return value into click, exactly like foo(bar()) calls bar and passes its return value into foo.
What you want to give click is a function to call. In your case, the simplest way is to use a wrapper function:
$('#one').click(function() {
info(this, '#Aarea');
});
...and update info to accept the element as an argument:
function info(element, a){
var source = $(element).data('source')
$(a).html(source)
console.log(source);
}
Updated Fiddle
Alternately, you can use Function#call to call your original info without changing it:
$('#one').click(function() {
info.call(this, '#Aarea');
});
Function#call calls a function, setting this during the function call to the first argument you give it (and then passing along any other arguments you give to it).
Updated Fiddle
I think your problem is that you're passing the evaluated function into your click handler.
The proper format is something more like this:
$('#one').click(function(){ info('#Aarea'); })
$('#two').click(function(){ info('#Barea'); })
Here's a fiddle with working code -http://jsfiddle.net/2548hkvg/
Alternatively, you could define the target area as a data attribute as well, and only have one function, seen in this fiddle - http://jsfiddle.net/k42ahykb/
In the code for that, we're defining info as our function expression that we pass to the click handler, and this is properly retained.
function info(e){
var source = $(this).data('source');
var target = $(this).data('target');
$(target).html(source)
console.log(source);
}
$('#one').click(info)
$('#two').click(info)
$('#one').click(info('#Aarea'))
You are calling the function here, so the result passed to .click() is undefined. Like #iabw said, you need to wrap it in a function expression so the click event can invoke info() successfully.
Just passthrough this from onclick function to info.
$('#one').click(function(){ info.call(this, '#Aarea'); })
$('#two').click(function(){ info.call(this, '#Barea'); })

Moving inline code into function, with object name generation

I am customizing Denis Gritcyuk's Popup date picker.
This pop-up script uses inline Javascript in a href link, to set the selected date into the input field, in the parent window, that is was called for. An example URL looks like:
<a href="javascript:window.opener.document.formname.field.value='03-10-2011';
window.close();">3</a>
The input field name, (e.g. document.formname.field), is passed to the script as a string parameter.
I would like to add things done when that link is clicked (e.g. change background color of field, set flag, etc.). So while this DOES work, it's getting ugly fast.
<a href="javascript:window.opener.document.formname.field.value='03-10-2011';
window.opener.document.formname.field.style.backgroundColor='#FFB6C1';
window.close();">3</a>
How would I move these inline commands into a JS function? This would give me much cleaner URLs and code. The URL would now look something like
3
with a function like (this example obviously does NOT work):
function updateField (str_target, str_datetime) {
var fieldName = "window.opener" + str_target;
[fieldName].value = str_datetime;
[fieldName].style.backgroundColor = '#FFB6C1';
// Set flag, etc.
window.close();
}
So any suggestions on how this can be done, please?
I'd prefer to hide the dom path tracing back from the current window back to the opener. It's appropriate to bake that into the function since the function will always be used in the context of that child popup. Then your function call is cleaner and more readable. Obviously, replace "myField" with the ID of the field you're intending to update.
3
function updateField ( str_date, str_fieldname ) {
var fieldToUpdate = document.getElementById( str_fieldname );
fieldToUpdate.value = str_date;
fieldToUpdate.style.backgroundColor = '#FFB6C1';
// Set flag, etc.
window.close();
}
You're acessing the property incorrectly. Try:
function updateField (str_target, str_datetime) {
var fieldName = window.opener;
str_target = str_target.split('.');
for (var i = 0; i < str_target.length; i++)
fieldName = fieldName[str_target[i]];
fieldName.value = str_datetime;
fieldName.style.backgroundColor = '#FFB6C1';
// Set flag, etc.
window.close();
}
The bracket notation ([]) is only used for properties of objects, not objects themselves. If you found my post helpful, please vote for it.
You can build a string and evaluate it as code using the eval function, but I would recommend against it.
There are a couple of things wrong with your code:
You cannot use the [] operator in a global context, you have to suffix it on an object, so you can say window["opener"] and this will be equivalent to window.opener, but there is no such thing as simply ["window"]
When navigating nested properties, as in window.opener.document you cannot navigate multiple levels using the [] operator. I.e. window["opener.document"] is not allowed. You must use window["opener"]["document"] instead.

Categories

Resources