I'm just curious, why is this event being loaded instead of triggering itself on click .
window.onload=initAll;
function initAll(){
var divPath = document.getElementsByTagName("div")[0];
var theLink = divPath.getElementsByTagName("a")[0];
theLink.onclick = myEvent(theLink);
};
function myEvent (myMan){
myMan.innerHTML="You're my maan,bro!!!";
return false;
};
10x for your kind help
BR
When you write theLink.onclick = myEvent(theLink), you're calling myEvent and assigning the result to onclick.
You need to create a separate function that calls myEvent with a parameter, and assign that to onclick:
theLink.onclick = function() { return myEvent(theLink); };
Because you are assigning the result of the function call myEventHandler(theLink) to the theLink.onclick property. What you are actually trying to do is the following:
theLink.onclick = myEventHandler
Which assigns a reference to the myEventHandler function to the theLink.onclick property. The argument passed to that function will be an event object, from which you can determine which object was actually clicked. Alternatively, you can create a closure:
theLink.onclick = function(event) {
myEventHandler(event, theLink);
};
This way you get the event object and a reference to the object which you assigned the event handler to, which is what (I guess that) you were trying to do in your code.
Its because as per your code you are assigning the value returned by the function myEvent as the theLink eventhandler instead of the function itself.
You should change the code to as follows:
window.onload=initAll;
function initAll(){
var divPath = document.getElementsByTagName("div")[0];
var theLink = divPath.getElementsByTagName("a")[0];
theLink.onclick = function(){ return myEventHandler(theLink)};
};
function myEvent (myMan){
myMan.innerHTML="You're my maan,bro!!!";
return false;
};
Related
My objective is to change the border style of button elements when they are clicked with javascript. I made a function setBorder and assigned to the onclick event on all button elements as:
function setBorder(myobj) {
myobj.style.borderStyle = "inset";
}
var menubtn = document.getElementById("menu_btn");
menubtn.onactive = setBorder(menubtn);
The problem here is that the border style is changed as soon as the page loads because when javascript is parsed the function setBorder() is executed due to the brackets (). Another alternative I thought was:
function setBorder() {
this.style.borderStyle = "inset";
}
var menubtn = document.getElementById("menu_btn");
menubtn.onactive = setBorder;
I thought this would take the object menubtn -- but this didn't happen. Why didn't this take the object menubtn?
I think there could be a way in which setBorder could be linked as the prototype object of all button elements. The prototype object would have a function func_SetBorder as it's property. Then we could call the func_setBorder as:
menubtn.onclick = menubtn.func_setborder;
This solution achieves what you're looking for via the use of a function closure.
var buttons = [ ... ]; // An array containing the buttons
for (let b of buttons) {
b.onactive = onActive(b);
}
function onActive(button) {
return function () {
button.style.borderStyle = 'inset';
}
}
Well, in JavaScript, when you use this keyword inside function in this it will points to an object on which you call your function. So, you have your function like this
function myFunc() {
this.do_smth;
}
and then you call it: my_obj.myFunc(), then, inside your myFunc thiswill points to my_obj.
Assume that you want to call your function with another object:
obj_foo.myFunc()
In this case this inside your function will points to obj_foo
If you want to call your function with different objects (but you must be sure that your objects have yhe same properties) its better to use call/apply or bind.
bind will say to your function "this is the scope which you should work with". But you should always bind your function to different objects in case of using this. More pretty and safely way is to use call/apply. You also should call your function with call/apply each time like with bind, but it looks more better.
So, your code should be like this: setBorder.call(menubtn)
What you want is binding or binding arguments. Javascript provides a native way to bind a function. If you want to bind arguments only, you can use this method as quoted from here:
Function.prototype.arg = function() {
if (typeof this !== "function")
throw new TypeError("Function.prototype.arg needs to be called on a function");
var slice = Array.prototype.slice,
args = slice.call(arguments),
fn = this,
partial = function() {
return fn.apply(this, args.concat(slice.call(arguments)));
// ^^^^
};
partial.prototype = Object.create(this.prototype);
return partial;
};
You would use it like this:
function setBorder(myobj) {
myobj.style.borderStyle = "inset";
}
var menubtn = document.getElementById("menu_btn");
menubtn.onactive = setBorder.arg(menubtn);
Or:
function setBorder() {
this.style.borderStyle = "inset";
}
var menubtn = document.getElementById("menu_btn");
menubtn.onactive = setBorder.bind(menubtn);
By CSS
#menuBtn:active{
border-style:inset;
}
By Javascript
You should try the eventlistener property as
menubtn.addEventListener("mousedown", setBorder);
menubtn.addEventListener("mouseup", removeBorder);
and inside the setBorder and removeBorder function you can use this
Assign it to a variable.
var functionName = function () {
//things
}
If you want this to be menubtn in the setBorder function, you need to bind it :
menubtn.onclick = setBorder.bind(menubtn)
I'm trying to create some select tags from within a closure function, and attach an event to them which calls another function within the closure.
Here's a very simplified version of my code:
var SomeClosure = function() {
this.build = function(){
var mydiv = document.getElementById('mydiv');
var newSelect = document.createElement('select');
newSelect.onchange = (function() {
var selfRef = this;
return function() {
selfRef.changeselection();
}
})();
mydiv.appendChild(newSelect);
};
this.changeselection = function(){
// do something
}
}
All I get, however, is 'selfRef.changeselection is not a function'. Where am I going wrong?
I don't need to pass in the value of the select, just call the function. If, however, I did need to pass in its value too, how would I do that?
Change your code to this:
var selfRef = this;
newSelect.onchange = (function() {
return function() {
selfRef.changeselection();
}
})();
The context inside immediate function is Window, so you get wrong reference. Also in this case you probably don't need IIFE at all, if this is all your code for onchange event handler.
To tell the true, i can call the function but just in hard-coded way. Instead of hard-coding the submit binding my getData function, i'd like to call the function by arguments. Please help me, how to do this.
Thanks.
formhandler = new xForm.Main(); // new formhandler
formhandler.setForm(this.formid); // fn.setForm(string) // configure the container, which has the form elements, or the form itself
modal = new xModal.Main(); // new modal handler
modal.setModal(this.modalid); // set modal element
modal.showModal(); // show
modal.bindClose(".cancel"); // bind closing classes
modal.bindSubmit(".submit", formhandler, "getData"); // bind submit to call formhandler.getData()
in the xModal.js
var xModal = xModal || {};
xModal.Main = function()
{
var self = this;
...
this.bindSubmit = function(classname, a, b)
{
this.closeclass = classname;
$("#"+this.target).find(classname).click(function(){
a.call(b); // edited after the original post, i forgot to replace the call's argument to b in the question excuse me for the inaccuracy
});
}
this function should call the getData in the xForm (here is the snippet from xForm)
var xForm = xForm || {};
xForm.Main = function()
{
var self = this;
this.target = "";
this.data = {};
...
this.getData = function()
{
getSingleElements();
getMultiElements();
return returnData();
}
Update:
I think i just found a method to do this, but please tell me if i made something uncorrectly, or you have a better solution for this problem (i'm pretty sure someone has)
I think, i have the correct method.
in the xForm i made a fn, which calls functions by parameters contains in the self (which is equals to this, actually)
var xForm = xForm || {};
xForm.Main = function()
{
var self = this;
this.callFn = function(func)
{
return self[func].call(this);
}
...
then i call the fn from the another class (xModal)
var xModal = xModal || {};
xModal.Main = function()
{
var self = this;
this.bindSubmit = function(classname, a, b)
{
this.closeclass = classname;
$("#"+this.target).find(classname).click(function(){
a.callFn(b);
});
}
then i just have to tell the xModal this:
modal.bindSubmit(".submit", formhandler, "getData"); // bind submit to call formhandler.getData()
so now the modal class will call the args[1]'s args[2] function. also able to give more parameters to the call fn by apply method.
works fine at me, but i don't know, maybe you can help me in make this better.
You bind a method name of a certain object to the submit event:
modal.bindSubmit(".submit", formhandler, "getData");
But you want to pass arguments to the method as well. This is not the Javascript way of doing it. Instead, just bind an anonymous function to the event, and call the method however you like from within this anonymous function:
modal.bindSubmit(".submit", function(){
formhandler.getData("My arguments");
});
What you see in my example is an anonymous function passed as an argument. In Javascript, there is no distinction between a value like a string or an integer, and a function. A function can be assigned to a variable, and passed as an argument.
To make it more clear, you can also write it like this:
var eventHandler = function(){
formhandler.getData("My arguments");
};
modal.bindSubmit(".submit", eventHandler);
This is called "first class functions", and are part of the "functional programming" paradigm.
Inside the event handler function, you still have access to the variables in the scooe it was created in, like the formhandler object. This is called a "closure".
Read up on this. It will boggle your mind at first, but it is really worth your time, as it will open your eyes to much simpler solutions.
From your example, I am not sure what the object modal is. If it is a jQuery element, my example should work right away, othewise, you would need to update your code to call the function passed in as the event handler, instead of calling a method on an object.
function test() {
this.str = "hello";
this.sayHello = function() {
document.write(this.str);
}
this.init = function() {
document.onkeydown = this.sayHello;
}
}
var testing = new test();
testing.init();
The above code should output "hello" on an onkeydown event.
But I get "undefined". How can I get this to work ?
The problem is with this.sayHello. When you assign the reference to the sayHello function on keydown, the reference to the context (object) is lost. When a key is pressed, this refers to the Document object as the callback is invoked as:
document.onkeydown(); // or for simplicity imagine - document.sayHello();
If you assigned the str variable on the document object, you would see the value logged,
document.str = "hello";
However, that is not what you'd want. You need to wrap the keydown event handler inside another function to preserve the context to that object. Two ways to go about this. You could either wrap the event handler inside another function, and preserve the reference to this.
this.init = function() {
var me = this;
document.onkeydown = function() {
me.sayHello();
};
}
Or, if you're using modern browsers, this has already been incorporated into ECMAScript 5 using the bind function.
this.init = function() {
var me = this;
document.onkeydown = this.sayHello.bind(this);
}
I am new to OOP and I am trying to rewrite a simple JS function as an object literal and then as a constructor function. I succeeded in writing the object literal version, but I clearly have a scope problem inside the anon function which handles the onclick event (inside my constructor function). Please let me know how to make the onclick event work.
Object Literal Version Which WORKS:
var submit = {
form_id : "",
submit_button_id : "",
submit_form: function(){
var button = document.getElementById(submit.submit_button_id);
var form = document.getElementById(submit.form_id);
button.onclick = function(){
form.submit();
return false;
}
}
}
addLoadEvent(function(){
submit.form_id = "form_vars";
submit.submit_button_id = "but_submit";
submit.submit_form();
});
Constructor Function Version Which DOESN'T WORK:
function SubmitForm(button_id, form_id){
this.submit_button = document.getElementById(button_id);
this.form = document.getElementById(form_id);
this.submit_form = function(){
// problem function below
this.submit_button.onclick = function(){
this.form.submit();
}
}
}
addLoadEvent(function(){
var form_to_submit = new SubmitForm("but_submit", "form_vars");
form_to_submit.submit_form();
});
P.S. I am aware that I should be using DOM API event handlers instead of HTML-DOM ones. I am just tackling one thing at a time.
this inside your function will not necessarily be the same as this in the constructor, it is decided by how you call that function. For instance, if you call a function f by doing f(), then this === window, if it is a method on an object x.f() then this === x. Also see Function:call and Function:apply.
Simplest way to solve this is to have a local variable in the constructor (like var me = this;) and then use me instead of this in the inner function, since that will not be overridden.
Read up on lexical scoping and closures if you want to learn more.