Having the following html:
<div id="plugin">
<script>
(function(){
this.do = function(e){
alert("cool!");
};
});
<script>
<div>
how do I call this.do (say from a parent element click button event handler)?
Maybe some more information will help advising on the right solution. It's a plugin, I want both markup and script to be part of the same file. I also want to be able to do something like:
$("#plugin").*controller*.do(); from outside of the plugin.
Here's a candidate solution, inspired by Scott's answer:
<div>
(function(){
var plugin = $("#plugin");
plugin.do = function(e){ alert("cool!"); };
});
</div>
then from outside:
$("#plugin").do();
any issues with it?
This looks like you can't, as the wrapper function doesn't have a name and does not self-execute. So the code never runs. If it would run, the this keyword in a global function refers to the window object and the inner function would be globally available.
(function(){
this.do = function(e){
alert("cool!");
};
})(); // <-- additional parentheses to self-execute the wrapper function
window.do === do; // true
// use
do();
// or
window.do();
// to call the inner function
But having such a wrapper function looks like you want to avoid global functions and variables (which is good for a number of well documented reasons). In that case you could define do as private method of your module and refer to it inside the wrapper function.
(function(){
var do = function(e){
alert("cool!");
};
var button = document.querySelector( 'button' ); // get the first button element
button.addEventListener( 'click', do, false );
})();
typeof do === 'undefined' // true; the function do is only available inside the wrapper function.
why are you against just doing?
<script>
function do(){
alert('cool!');
}
<script>
you could do :
<script>
window.do = function(){
...
}
</script>
then some where else:
window.do()
You can't. The outer function expression isn't called or assigned anywhere, so it will be discarded without ever evaluating the inner function expression.
If you want to bind the function somewhere, call addEventListener on the element you want to assign it to and pass it as the second argument.
Related
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.
I have a function that I want to use in order to expand menus in various places. I expect it to be triggered on a click of menu associated button, but at the moment it is being called on page load (I assume from within document ready), and class 'expanded' is added without clicking on a buton. I am confused to why this happens, as it should be called .on('click' ..
jQuery(document).ready(function ($) {
'use strict';
$('#btn-expand-mobile-nav').on('click', showMenu('#side-navigation'));
});
function showMenu(menu) {
var x = $(menu),
y = 'expanded';
if (x.hasClass(y))
x.removeClass(y);
else
x.addClass(y);
}
You are calling the function immediately. Instead defer the execution using an anonymous function:
$('#btn-expand-mobile-nav').on('click', function(){
showMenu('#side-navigation')
});
If there were no parameters you could have done this:
$('#btn-expand-mobile-nav').on('click', showMenu);
Simplistic explanation for #skobaljic:
By using the function name alone, you are pointing at the variable showMenu and saying call this later as a function.
By using function(){} you are saying, here is a temp variable, containing a function, that you can call later.
e.g. it is the same as:
var temp = function(){
showMenu('#side-navigation')
}
$('#btn-expand-mobile-nav').on('click', temp); // No parenthesis on temp
As #Dave Newton rightly points out, this can be simplified using toggleClass:
$('#btn-expand-mobile-nav').on('click', function(){
$('#side-navigation').toggleClass("expanded");
});
How can I use "this" in this case?
I got an error.. The page can't set display at null or undefined.
<button onclick="myFunction(this)">
<script>
function myFunction() {
this.style.display='none';
}
</script>
You can use func.call to bind a context for that function invocation (otherwise in your case it will be pointing the the global object (window) ):
myFunction.call(this);
or with myFunction(this)
You should do:
function myFunction(elm) {
elm.style.display='none';
}
An even better idea is to register the click event using addEventListener instead of with onclick inline in the HTML:
var theButton = document.getElementById("theButton");
theButton.addEventListener("click", function(e) {
var originalElement = e.srcElement || e.originalTarget;
originalElement.style.display = 'none';
});
Of course, you'll need to either give the button the same id I did -- theButton -- or otherwise retrieve it, but this is a much more flexible and modern way to handle the event.
I have a function localised to the main function and i want to use this to call it but it doesn't seem to work.
My code has:
function option(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity
transition_opacity(div_id,opacity,0,function(){this.load});
function load(){
console.log('test'); //does not happen
}
}
Have i misunderstood the use of this or is the scope lost when i use function(){} to call load?
From your code it is not obvious, what object this could refer to. It depends on how option is called. However, if you define the load function inside of the option function anyway, it is best to just reference it directly. You will have to move the declaration of test above the transition_opacity call though:
function option(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity;
function load() {
console.log('test');
}
transition_opacity(div_id,opacity,0,load);
}
As you can see, I just reference load directly. You could make another function which calls the load function inside (i.e. function() { load(); } – note the parentheses which calls the function) but that would give you no benefit but would just add another unneeded function to the stack. So just refer to the actual function itself.
For more information on the this keyword, check out this question. Spoiler: It’s more complicated than you would expect.
The scope of this is lost in this instance, probably pointing to the document. You can capture this to a variable in the outer scope to make this work as intended.
var context = this;
transition_opacity(div_id,opacity,0,function(){context.load();})
The above will not work however. This is because load does not exist on the context of this. You would need to define the load function as such:
context.load = function(){
console.log('test');
}
Both.
First, your load function is not a member/property of any this, the way you have it coded. Your load function is simply a nested function that exists within your option function, as has been sort of implicitly noted in other responses.
In your option function, if you want 'load' to become a member of 'this', you'd need to say so, like this:
function option(){
this.load = function(){}; // now load is actually a property of whatever this is
}
Second, you and the other poster are correct that 'this' is no longer the same 'this' by the time your anonymous function is called.
Whenever you call a function, a brand new 'this' is created and exists within the scope of that function. If you just call a function like this:
transition_opacity(args);
.. then within transition_opacity, 'this' just refers to the window object, or maybe window.document. For 'this' to refer to anything other than window or window.document, you need to (in effect) do one of the following:
myObject.transition_opacity(args);
transition_opacity.call(myObject, arg1, arg2, ..);
transition_opacity.apply(myObject, argArray);
or
var myObject = new transition_opacity(args);
In each of those cases, within transition_opacity, 'this' refers to myObject (or, well, in the last case, it refers to a new object that is being created and assigned to myObject).
Here is a way to do what it looks like you're trying to do:
var MyNamespace = {
option: function(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity;
var _this = this;
transition_opacity(div_id,opacity,0,function(){
// Careful! Inside here, 'this' is just window or window.document,
// unless transition_opacity sets it to something using call or apply,
// in which case that 'this' is probably not the 'this' you want.
// So carefully refer to the saved instance of 'this':
_this.load();
});
},
load: function(){
console.log('test'); // now it should happen
}
}
.
.
MyNamespace.option(room, slot); // inside option, 'this' is MyNamespace.
Here's another way to do it:
function MyClass(){};
MyClass.prototype = {
// all the same stuff that is in MyNamespace above..
};
.
.
var myObject = new MyClass();
myObject.option(room, slot);
Clear as mud?
Just use
transition_opacity(div_id,opacity,0,load);
You have defined a 'load' within another function as an 'Function Declaration', so now it is only accessible within 'option' function and in other functions defined in this one by name 'load'. You can't access it by using 'this.load' no matter what 'this' is. If you want to access 'load' function as 'this.load' you can try this example to understand how 'this' keywoard works
// Function Declaration
function f1(callback){
callback();
};
// Function Declaration
function f2(){
// Function Expression
this.load = function(){
console.log("test");
};
f1(this.load);
};
var obj = new f2(); // test, this == obj, so obj.load() now exists
obj.load(); //test, this == obj
f2(); //test, this == window, so window.load() now exists
load(); //test, window is the global scope
I am writing some useful functions for my webpage for my webpage. The functions will be inside an anonymous function and will be called from outside the function. When I try to call the functions I get an error. This is how I am constructing it:
(function(){
var fx ={
pop : function(msg){
alert(msg);
}
};
fx = window.fx;
})();
window.onload = fx.pop('hi');
Does anyone know how I might do this? I know this is possible because jQuery and other javascript libraries are written like that.
When you do fx = window.fx; you are overwriting the fx which is in local scope of anonymous function. If you want access to it outside in the global scope you would need to do
window.fx = fx;. And Seems like you want to invoke the function pop on load and not when registering on load, Which is what you are trying to do here window.onload = fx.pop('hi'); This will invoke pop immediately and set the result of method as callback for load event (which is undefined as your method doesn't return anything; unless the method return another function that needs to be invoked after load this becomes useless). Instead you may want to try this way.
window.onload = fx.pop.bind(this, 'hi'); //Now this will get invoked only after load event is completed, it bind the current context to the function pop with the argument `hi`
or
window.onload = function(){
fx.pop('hi'); //Now this gets invoked only after load event is completed
};
So you can try:
(function(){
var fx ={
pop : function(msg){
alert(msg);
}
};
window.fx = fx;
})();
window.onload = function(){
fx.pop('hi')
};
are you sure jquery and other javascript libraries are written like that? I don't know of a simple way to gain access to the scope of a function, from outside that function. this seems like an unusual objective so please explain what problem you are attempting to solve with this technique, perhaps there is a more appropriate strategy.
For instance you could try:
var fx;
(function(){
fx ={
pop : function(msg){
alert(msg);
}
};
fx = window.fx; // this will probably overwrite your previous object with undefined
})();
window.onload = fx.pop('hi');