I am trying to add some event listener to document, but for some reason it looks like the click event is never fired, because the callback is never called:
function NotJquery(element) {
this.element = element;
return this;
}
NotJquery.prototype.eventFired = function(event, callback) {
console.log('in NotJquery prototype');
return function (event, callback) {
element.addEventListener(event, callback, true);
};
};
var $ = function(element) {
return new NotJquery(element);
};
function Test() {
}
Test.prototype.addListener = function() {
console.log('in Test prototype');
$(document).eventFired('click', function() {
console.log('click event fired');
});
};
(function() {
var test= new Test();
test.addListener();
}());
Both the messages: "in Test prototype" and "in NotJquery prototype" are logged in the console, but when I click somewhere in my document the message "click event fired" is not output in the console. I do not see what is wrong with my code. Anybody has an idea to get it working?
http://jsfiddle.net/Nn3tZ/1/
Your client code is expecting something like this:
NotJquery.prototype.eventFired = function(event, callback) {
this.element.addEventListener(event, callback, false);
};
Working demo: http://jsfiddle.net/Nn3tZ/2/
element is not defined within your eventFired function (but that's not the only problem). Here's a minimal update:
NotJquery.prototype.eventFired = function(event, callback) {
var self = this; // <== Change 1 of 2
console.log('in NotJquery prototype');
return function () {
self.element.addEventListener(event, callback, true);
// ^-- Change 2 of 2
};
};
Unlike some other languages (Java, C#), this is not optional when referring to a property on the current object. Separately, the function you're creating within eventFired won't have the right this, so that's why I've stowed it away as self and then used self within the generated function (which is a closure).
Separately, you're passing event and callback into eventFired but then also declaring them on the generated function (it's not at all clear to me why you're generating a function there at all), so the ones you pass into eventFired are never used.
More reading (on my anemic blog):
Mythical Methods
You must remember this
Closures are not complicated
Related
I am creating a function that handles a bunch of stuff around pagenating and sorting a table. It contains a key function that submits the db query and updates the display table.
I want to be able to access that inner function/method from both inside the function and also from outside on the object created.
testFunction = function() {
keyMethod = function() {
console.log('ya got me');
};
document.getElementById('test').addEventListener('click', function (e) {
keyMethod();
});
keyMethod();
};
myTest = new testFunction();
myTest.keyMethod();
testFunction = function() {
this.keyMethod = function() {
console.log('ya got me');
};
document.getElementById('test').addEventListener('click', function (e) {
// would have to use bind here which then messes up trying to
// find the correct target etc.
keyMethod();
});
this.keyMethod();
};
myTest= new DrawShape();
myTest.keyMethod();
Creating it the first way means that the keyMethod function is available everywhere within the testFunction but I cant call it from outside.
Creating it the second way means I can do myTest.keyMethod but I then cant call it from within an inner function without using bind everywhere.
Is there a better way..?
You could replace the function provided as callback with an arrow function or use bind the function first like you already said.
testFunction = function() {
this.keyMethod = function() {
console.log('ya got me');
};
// Replace callback by simply providing the function to call.
// This works as long as you don't use the `this` keyword inside the
// provided function.
document.getElementById('test').addEventListener('click', this.keyMethod);
// If your callback method does use the `this` keyword you can either use an
// arrow function or bind the function up front.
document.getElementById('test').addEventListener('click', event => this.keyMethod());
document.getElementById('test').addEventListener('click', this.keyMethod.bind(this));
this.keyMethod();
};
console.log("constructor output:");
myTest = new testFunction();
console.log(".keyMethod() output:");
myTest.keyMethod();
console.log("click event output:");
<button id="test">test</button>
I am learning how to reverse engineer an existing javascript code and I've ran into a few issues which is due to my lack of understanding how core javascript works. The code is below along with a screen shot of the comments I have.
The code starts out with var warper being declared.
And then warper variable equals a function inside a function? Why isn't it the usual call of function Warper(), but its inside another function?
I noticed the use of _this. How is that different from the regular this that is usually used?
The #btn-submit id is set to activate when it is clicked on. I can see that it calls the click_submit function, but why is it Warper.prototype.click_submit instead of just click_submit()?
And my final question, which is what I really want to do is call the click_submit function via js without having to click on the #btn-submit button.
Question: How do I call the warper.click_submit function using js without the need to click a button? I'm trying to integrate this into another piece of my code.
I tried warper.prototype.click_submit and it doesnt do anything. I'm assuming its because its inside a function in a function?
(function() {
var Warper;
Warper = (function() {
function Warper() {
this.check_compatibility();
this.attach_ux();
if (window.SALT_DEFAULT != null) {
$('#salt').val(window.SALT_DEFAULT);
$('#salt').attr('disabled', true);
$('.salt-label').text('Prefilled salt');
}
}
Warper.prototype.check_compatibility = function() {
if (typeof Int32Array === "undefined" || Int32Array === null) {
return $('.form-container').html('<p>\n Sorry, but your browser is too old to run WarpWallet, which requires Int32Array support.\n</p>');
}
};
Warper.prototype.attach_ux = function() {
$('#btn-submit').on('click', (function(_this) {
return function() {
return _this.click_submit();
};
})(this));
$('#btn-reset').on('click', (function(_this) {
return function() {
return _this.click_reset();
};
})(this));
return $('.what-salt').on('click', (function(_this) {
return function() {
return $('.salt-explanation').toggle();
};
})(this));
};
Warper.prototype.click_submit = function() {
$('#btn-submit').attr('disabled', true).html('Running...');
$('#btn-reset').attr('disabled', true).html('Running...');
$('#passphrase, #salt, checkbox-salt-confirm').attr('disabled', true);
$('.progress-pbkdf2, .progress-scrypt').html('');
$('.progress-form').show();
return warpwallet.run({
passphrase: $('#passphrase').val(),
salt: $('#salt').val(),
progress_hook: (function(_this) {
return function(o) {
return _this.progress_hook(o);
};
})(this),
params: window.params
}, (function(_this) {
return function(res) {
$('#passphrase, #checkbox-salt-confirm').attr('disabled', false);
if (window.SALT_DEFAULT == null) {
$('#salt').attr('disabled', false);
}
$('#private-key').val(res["private"]);
_this.write_qrs(res["public"], res["private"]);
return console.log;
};
})(this));
}; //click_submit
return Warper;
})(); // Warper End
$(function() {
return new Warper();
});
}).call(this); // End Function
The code starts out with var warper being declared.
And then warper variable equals a function inside a function? Why isn't it the usual call of function Warper(), but its inside
another function?
It is inside another function to create it's own scope. This practice is used mainly to separate non relative code and prevent global variables.
I noticed the use of _this. How is that different from the regular this that is usually used?
_this is just a variable that is set to point to outer this. Everytime you call a function it has own this (depending on how you called the function). So if define callback inside another function, and you need to refer to this of that outer ("another") function, you can save it temporarily to variable. This temporarily variables are usually referred to as _this, that or self.
The #btn-submit id is set to activate when it is clicked on. I can see that it calls the click_submit function, but why is it
Warper.prototype.click_submit instead of just click_submit()?
If you define function on prototype, every instance will use that same function. If you would define it on this.clik_submit = function(){...} then every instance would have to have it's own copy of that function. Last option is to just define function click_submit(){...} inside scope, but then the function wouldn't be accessible from outside the scope.
And my final question, which is what I really want to do is call the click_submit function via js without having to click on the
btn-submit button.
You need to gain access to warper instance to be able to call the click_submit function. Without it (and without being able to update the code) it is not possible to call it. But you could consider creating click event on button yourself which would trigger the function. Using jquery this is as easy as $("#btn-submit").click();
Warper is an object.
Warper.prototype.attach_ux = function() {
$('#btn-submit').on('click', (function(_this) { //2
return function() {
return _this.click_submit(); //3
};
})(this));//1.
on //1 'this' refers to the Warper object and is bound to the scope of Warper.prototype.attach_ux function.
on //2 _this is the name of argument which refers to the value passed at //1.
Since //1 refers to the Warper object the click_submit method is called.
This is IIFE pattern of function invocation.
If you were to call
$('#btn-submit').on('click', function(_this) {
return function() {
return _this.click_submit();
};
})
Here _this would refer to the click event and we would not be able to access the defined method conviniently. But we are able to pass the Warper object using IIFE pattern and access it easily.
I have an object contain many methods among them two methods, the first to add event to an element, and the other to remove that event.
event: function (event, callback, capture) {
var _this = this;
if (document.addEventListener) {
var fn = function(){callback.call(_this);}
this[0].addEventListener(event, fn, capture || false);
this.eventFunc = fn;
}
return this;
},
remEvent: function (event) {
if (document.removeEventListener) {
this[0].removeEventListener(event, this.eventFunc);
}
return this;
}
When usage:
oo('#on_btn').event('click', function(){console.log("clicked")});
oo('#on_btn').remEvent('click');
In the previous code you seen that I use a public variable this.eventFunc to save a reference to the callback function. and then I have used it in removeEventListener. but the problem is that public variable is always undefined and thus the removeEventListener does not works fine.
Now, how can I transfer the reference of callback to the removeEventListener function to remove the event that I have added before ?
I was messing around with IndexedDB and I realised that I don't really get event handling in JavaScript.
So here's the code:
var request = indexeddb.open(bla, version);
request.onsuccess = function (event) { };
So the open-method returns a IDBOpenDBRequest object, which, according to Mozillas site, inherits from IDBRequest, which apart from properties and methods also has event handlers, one of them being onsuccess:
https://developer.mozilla.org/en-US/docs/Web/API/IDBRequest.onsuccess
So on the mozilla site, onsuccess is just function () { }
Now, when the database was opened sucessfully, the "onsuccess" event fires and the appropiate event handler is called, in this case the function that I defined. But how exactly does that happen?
The request variable contains an instance of the IDBOpenDBRequest. So when I write request.onsuccess = somefunction(), am I overwriting the default function of the IDBRequest-class?
I dont get why I can write request.onsuccess = somefunction(event) { } and how the event is passed to that function.
EDIT:
function myObect() {
this.open = function(a,b,c) {
if (c > 20) {
this.success("String");
}
};
};
var myrequest = new myObect();
myrequest.open(4,2,21);
myrequest.success = function (ev) {
console.log(ev);
};
To create a similar api, you can do something like:
function open(a, b, c) {
var request = {};
if(c > 20) {
setTimeout(function() {
if(typeof request.success === "function") {
request.success("String");
}
}, 1);
}
return request;
}
var myrequest = open(4, 2, 21);
myrequest.success = function(ev) {
console.log(ev);
};
Here, setTimeout is asynchronous so the callback function is not executed immediately. When any asynchronous task is run in JavaScript, the currently executing code will run to completion before any callback is called. So success is guaranteed to be set before request.success called.
The Indexed DB open call similarly runs an asynchronous task, and then dispatches events when it is finished which will eventually call your callback function.
I overwriting the default function of the IDBRequest-class
Looks like there is no default behavior, so you just set up your own func.
I am looking for a good technique to get away from what I am tempted to do: to set a global variable.
The first time someone runs a function by clicking a button it triggers an initial function to turn a few things into draggables. Later, if they click the button a second time I want to determine if the init function has been initialized, and if so to not call it again. I could easily do this by setting a global variable from the init function and then checking that variable from the click function, but I'm wondering how to do this without setting a global variable. I would really like an example of a way to do this.
You could add a property to the function:
function init() {
init.called = true;
}
init();
if(init.called) {
//stuff
}
While #Levi's answer ought to work just fine, I would like to present another option. You would over write the init function to do nothing once it has been called.
var init = function () {
// do the initializing
init = function() {
return false;
}
};
The function when called the first time will do the init. It will then immediately overwrite itself to return false the next time its called. The second time the function is called, the function body will only contain return false.
For more reading: http://www.ericfeminella.com/blog/2011/11/19/function-overwriting-in-javascript/
Why don't you just check to see if your draggables have a class of draggable on them?
if ($('.mydiv').is('.draggable')) {
//do something
}
Function.prototype.fired = false;
function myfunc() {
myfunc.fired = true;
// your stuff
};
console.log(myfunc.fired) // false
myfunc();
console.log(myfunc.fired) // true
What you could do is unhook the init function from the prototype.
var Obj = function () {
this.init = function () {
document.write("init called<br/>");
this.init = null;
}
}
var o = new Obj();
if (o.init) document.write("exists!<br/>");
o.init();
if (o.init) document.write("exists!<br/>");
o.init();
The first if will be true and print exists! but since the function removes itself, the second if will fail. In my example, I call the second init unconditionally just to show that nothing will happen, but of course you could call it only if it exists:
if (o.init) o.init();
http://jsfiddle.net/coreyog/Wd3Q2/
The correct approach is to use the Javascript Proxy APIs to trap the function calls using apply handler.
const initFun = (args) => {
console.log('args', args);
}
const init = new Proxy(initFun, {
apply(target, thisArg, args){
target.calls = target.calls ? target.calls + 1 : 1;
return target.apply(thisArg, args);
}
});
init('hi');
console.log(init.calls); // 1
init('hello');
console.log(init.calls); // 2