'this' binding in Reusable Functions? - javascript

I have put together a small script as part of a larger quiz project and am struggling to understand why the this keyword is being set in the function before it is called. Here is my code:
$(document).ready(function ($) {
function nextCard() {
console.log('yes');
$(this).closest('.card').hide();
$(this).parent().next().show();
}
$("#start").on('click', function (e) {
e.preventDefault();
//First card to appear
nextCard();
});
$("#next").on('click', function (e) {
e.preventDefault();
nextCard();
});
});
Why would 'this' not be set to element #start for instance?

Within nextCard(), this will refer to the window as that's the default scope. Hence your DOM traversal methods most likely are not working as you expect them to.
Assuming you want this within the function to refer to the clicked #start or #next element, you could provide the reference of nextCard() to the event handler methods, like this:
$(function($) {
function nextCard(e) {
e.preventDefault();
console.log('yes');
$(this).closest('.card').hide();
$(this).parent().next().show();
}
$("#start, #next").on('click', nextCard);
});

Why would 'this' not be set to element #start for instance?
Why would it be? It's not that it can sense what you want it to do.
Use Function#call to define what object this should point to during the call. If you don't explicitly define it, this will default to the global object (Window in browsers).
$(document).ready(function ($) {
function nextCard() {
console.log('yes');
$(this).closest('.card').hide();
$(this).parent().next().show();
}
$("#start").on('click', function (e) {
e.preventDefault();
//First card to appear
nextCard.call(this);
});
$("#next").on('click', function (e) {
e.preventDefault();
nextCard.call(this);
});
});
Using someFunction.call(this); will effectively "transfer the current meaning" of this to the called function, or more technically, call someFunction in the context of whatever object this is referencing at the moment.
jQuery does something like the above automatically - it sets this for you to the proper DOM element when it calls event handlers. You can make use of the automatic this handling like #Rory McCrossan's answer shows – or you handle this yourself.

Related

How to access function inside of function?

today my question is asking how I would access a function inside a function. So, for example, I have a button, and if I click it, it would alert. The thing is, if you have a function surrounding the function, the inside function with the alert would not alert.
Here's an example:
html:
<button onclick="doStuff()">Alert</button>
js:
function nothing() {
var doStuff = function() {
alert("This worked!")
}
}
so the doStuff() function would not work. Can someone help me find a way to access it?
#Joseph the Dreamer is ultimately correct, but if you were dead set on calling a function that's nested in another function you could use an OOP approach.
Create a javascript "class" object and scope your function to "this":
function Nothing() {
this.doStuff = function() {
alert("works");
}
}
Next you add an id to your button,
along with a click event listener
Then, inside your click event you can call doStuff within the Nothing "Class" function like this:
var object = new Nothing();
object.doStuff();
https://jsfiddle.net/me7fek5f/
You can't. That's because it's enclosed in a scope that you can't really access globally. The only way you can access it is to expose it somewhere outside nothing.
Is this a homework question?
You're probably asked to do something like this:
function nothing() {
var doStuff = function() {
alert("This worked!")
}
var yourButton = getYourButton();
attachClickListener(yourButton, doStuff);
The implementations of getYourButton and attachClickListener are left to the reader.

Cache a variable exclusively on a function

Is there a way to cache a global variable for a function within a group of functions, without calling that function directly from another?
For example, if I have a group of functions wrapped in a parent function like this:
function parentFunction() {
var myVariable;
someDiv.addEventListener('click', function (e) {
myVariable = e.target;
});
anotherDiv.addEventListener('click', function (e) {
// use myVariable without it changing when the above is fired again.
});
}
The global variable is declared at the start, it is given a value in the first function, which carries over to the second for use.
But how can I stop it from continually updating in the second function, if the first function fires again?
Could I add another event-listener inside the second function to check if the first fires again and ensure the variable doesn't change?
You can set the variable only once in the first function:
someDiv.addEventListener('click', function (e) {
if (!clickedLink) {
clickedLink = e.target;
}
});
Or, you can apply any logic you want there. Sometimes, saving state like this in a semi-global for later use in a different event handler is a warning sign that you might have a design issue. If you explain more about what you're really trying to do, we could offer an opinion on whether there's a better way to solve your design issue.
Not sure if I fully understand the question. If you want to have two distinct bindings, you need two variables. Maybe so:
function parentFunction() {
var myVariable, anotherVariable;
someDiv.addEventListener('click', function (e) {
myVariable = e.target;
if (!anotherVariable) {
anotherVariable = e.target;
}
});
anotherDiv.addEventListener('click', function (e) {
// use anotherVariable
});
}

What's the elegant way of binding multiple elements with different event respectively using same event handler?

I have both $(document) and $(window), they are bound with 'ready' and 'resize' event respectively. They are sharing the same event handler.
Code:
$(window).on('resize', function () {
Shared code
});
$(document).ready(function () {
Shared code
});
Instead of the style above, is there a conventional way of handling this to make the code clean and simple>
It's very simple actually.
var handler = function (event) {
// Whatever you want to handle
};
$(window).on('resize', handler);
$(document).ready(handler);
Another option if you don't want to pollute global namespace is to use an immediately executed anonymous function.
Building upon TheShellfishMeme's answer:
// handler will not be defined at this point
(function() {
var handler = function (event) {
// Whatever you want to handle
};
$(window).on('resize', handler);
$(document).ready(handler);
})();
// handler will not be defined at this point

Calling jQuery document.ready functions by hand

If I make an AJAX request and want to call all functions that were set up by $(document).ready(). How can I do it? Thank you
$(document).ready();
If that doesn't work, try this:
function startup() {
// All your functions in here.
}
$(document).ready(startup);
And after your AJAX request is finished:
startup();
The easiest way is to use a shared function:
$(document).ready(function() {
setup();
});
$.post('/', {}, function() {
setup();
}, 'json');
But if you're using it to re-assign listeners, you would probably be able to get away with assigning them before they're created, like this:
$(document).ready(function() {
$(document).delegate('.my-button', 'click', function() { });
});
Using this code, all .my-button clicks will be handled by your custom function, regardless of whether the button existed in your DOM upon DOMReady.
Note that:
$(document).ready(function() { ... }); can be minimized to $(function() { ... });
If you're using jQuery 1.7+, prefer .on over .delegate: $(document).on('click', .my-button', function() { });
Prefer narrower context over broader, i.e. $('#close-parent').delegate over $(document).delegate
Instead of triggering document.ready by hand (which would be bad practice IMHO), make a function that's called setup which sets up all listeners etc. and invoke this function when you need to re-apply things etc.

Check event target when using document.attachEvent

I have the following code...
document.attachEvent("onclick", get_func(obj, "on_body_click", "event_target_here"));
I am attaching a global function get_func() to the event onclick. get_func() returns reference to a function defined in a function object something like this..
function get_func(obj, funcname, params) {
if(funcname == "check") {
return obj.checkTarget(params);
}
}
Now in the function checkTarget(), I need to check which DOM object was clicked upon. How can I do this? I understand that I need to send the target of onclick event to the global function somehow.
Can somebody throw some light on this?
Regards
If you want to pass the object that was clicked on into the global function, you can modify your event attachment to use the click event's source element to something like this:
document.attachEvent("onclick", function(e) { get_func((e || event).srcElement, "on_body_click", "event_target_here") });
Then you could pass that object down to the checkTarget function.

Categories

Resources