Pass parameter to bound function - javascript

I am running into an issue where I want to pass an 'event' parameter to a function which is being called from a JQuery eventListener.
$('#todoRemove').on('click', this.removeTask(event));
This immediately calls the function when the page is loaded, then does not work when pressing the button which would kick off the event. What can I change to make it so it calls the method in the prototype but passes the event parameter?
TaskCtrlr.prototype = {
init: function () {
this.setupEventHandlers();
},
setupEventHandlers: function () {
$('#addTask').on('click', this.addTask.bind(this));
$('#todoRemove').on('click', this.removeTask.bind(this));
/* $('#todoComplete').on('click', this.completeTask.bind(this));
$('#doneRemove').on('click', this.removeTask.bind(this));*/
},
addTask: function () {
let taskInput = this.view.getTaskInput();
let newTask;
if (this.model.tasks.todo.length == 0) {
newTask = new Task(0, taskInput.title, taskInput.desc, false);
} else {
let id = this.model.tasks.todo[this.model.tasks.todo.length - 1].id + 1;
newTask = new Task(id, taskInput.title, taskInput.desc, false);
}
this.model.addTask(newTask);
this.view.addTodoTask(newTask);
},
completeTask: function (event) {
console.log('wwwwww');
console.log(event.target.id);
},
removeTask: function (event) {
console.log('eeeeee');
console.log(event.target.id);
}
};
EDIT: CURRENT SOLUTION
$('#todoRemove').on('click', event, removeTask);
ERROR:
jQuery.Deferred exception: removeTask is not defined ReferenceError:
removeTask is not defined

Why do you want to pass event? What does it even refer to?
The event object is passed by the caller of the event handler, which is jQuery. You should do exactly the same as you do for the other handlers:
$('#todoRemove').on('click', this.removeTask.bind(this));
jQuery will pass the event object to the function without you having to do anything.

This immediately calls the function when the page is loaded
$('#todoRemove').on('click', this.removeTask(event));
Yes, it will call it because during registering a call back, you are not really registering a callback but calling your function using this code:
this.removeTask(event)
Instead you need to do this. I am not sure what event is but the 2nd argument you can use to pass something to the callback:
$('#todoRemove').on('click', event, removeTask);
And you can define removeTask like this:
function removeTask( event ) {
//...
}
Here is an example you can play with to get comfortable:
function greet( event ) {
alert( "Hello " + event.data.name );
}
$( "button" ).on( "click", {
name: "Karl"
}, greet );
If you do not pass anything, jQuery will still pass the a parameter to you which contains the event info as shown below:
function greet2( event ) {
alert( "Hello " + event.target.id );
}
$( "button" ).on( "click", greet2 );
There is more info here.
<== Fiddle Me ==>

Related

Scope of this in Click Handler

I have something similar to the following but I get the error: "this._toggle is not a function"
function handler(){
this._toggle();
}
SelectFX.prototype._toggle = function(){
...
this.removeEventListener('click', handler);
}
this.addEventListener('click', handler);
which I'm guessing is to do with the scope that addEventListener creates,
I would of thought then that adding this to a variable would fix but this code:
var self = this;
function handler(){
self._toggle();
}
SelectFX.prototype._toggle = function(){
...
this.removeEventListener('click', handler);
}
this.addEventListener('click', handler);
But the above gives the error "Cannot read property '_toggle ' of undefined"
If I use an anonymous function like below for the click handler it works fine but I need to Remove the Click Event later on, please help
SelectFX.prototype._toggle = function(){
...
}
this.addEventListener('click', function(){
this._toggle(); //Works fine but I need to remove this addEventListener later on
});
I've create a Gist here with the Full plugin https://gist.github.com/grassed/ce76d9b2a5fa6ab9e5be which centers around this.selPlaceholder.addEventListener( 'click', clickHandler);
You can use the native bind function to pass the object that should represent this in the function called. You can use that also for event listeners. In the example below, I pass in someObject to be this when someListener is being called.
var el = document.getElementById("clickable-span");
var someObject = {
clickCount: 0,
someListener: function(){
this.clickCount++;
this.showCount();
el.innerText = 'Click me again';
},
showCount: function(){
document.getElementById('target-span').innerText = 'You clicked ' + this.clickCount + ' time(s)';
}
}
// use bind to pass in what `this` should refer to in the someListener method
// we want `this` to point to someObject so we can use the clickcount and such
el.addEventListener(
"click",
someObject.someListener.bind(someObject)
);
<button id="clickable-span">Click me</button>
<hr />
<span id="target-span"></span>

addEventListener seems to trap my global variable

I have a non-jquery script with an addEventListener on a buttonclick. This works fine the first run but I want it to change "sendingurl" to some other value after the first click. (the succesfull insert of form becomes an update form). However, even though sendingurl fills with the new id value, it doesnt change after the event is fired again. Instead by the second click it fires the newly created event tohether with the old one with the old value.
The resulting values in console.log:
1st click: event "click" is fired with url: input.php
2nd click:
event "click" is fired with url: input.php
event "click" is fired with url: update.php?io=items&id=693
So I want to get rid of the input being triggered after the first click. Does someone know how to solve this?
var itemid = getHash();
ini(prepare); // using window.onload to execute
function prepare() {
if (itemid) {
// update
var sendingurl = 'update.php?io=items&id=' + itemid;
} else {
// input
var sendingurl = 'input.php';
}
// submitevent
æ($("submitBtn"), 'click', function() {
console.log("event \"click\" is fired with url: " + sendingurl);
var json = new FormData(document.forms[0]);
ajax(sendingurl, json, submittedInput);
});
}
// callback function after ajax did his magic
function submittedInput(response) {
if (response) {
if (!itemid) {
itemid = response;
prepare();
}
} else {
$("status").innerHTML = "something went wrong with the input";
}
}
// function to add events without the use of jquery or prototype
function æ(el, evType, fn, useCapture) {
if (el.addEventListener) {
el.removeEventListener(evType, fn, useCapture);
el.addEventListener(evType, fn, useCapture);
return true;
} else if (el.attachEvent) {
el.detachEvent('on' + evType, fn);
var r = el.attachEvent('on' + evType, fn);
return r;
} else {
el['on' + evType] = fn;
}
}
The first time through, there is no event handler to remove and your anonymous function is added as an event handler. The anonymous function creates as closure, so the value of sendingurl is now "constant" no matter how the external sendingurl changes. That is why you are getting the old value.
The second time through, the event handler function being passed to removeEventListener is not yet tied to an event because the second anonymous function is not the same function as the anonymous function on the first pass. So no event handler is removed. You then add a second event with the new anonymous function with the revised value of sendingurl. That is why you are seeing both functions fire.
Convert your anonymous function to a normal function and use the normal function name instead.

Jquery click functions runs before clicking

I want my jquery to load a function when a button is clicked.
This works fine:
$(document).ready(function() {
$("#register").click(function() {
alert("button");
});
This one will show the test() function before the document loads:
$(document).ready(function() {
function test(param1, param2){
alert("param1: "+param1+" param2: "+param2);
}
$("#register").click(test("a","b"));
});
How can i fix this ?
$(document).ready(function() {
$("#register").click(function() {
alert("button
});
should be:
$(document).ready(function () {
$("#register").click(function () {
alert("button");
});
});
And
$(document).ready(function() {
function test(param1, param2){
alert("param1: "+param1+" param2: "+param2);
}
$("#register").click(test("a","b"));
});
should be
$(document).ready(function () {
function test(param1, param2) {
alert("param1: " + param1 + " param2: " + param2);
}
$("#register").click(function () {
test("a", "b");
});
});
$(document).ready() fires once the DOM is ready.
I think your problem is in this code:
$("#register").click(test("a","b")); // I suppose it is executing test().
you just pass the parameters through event handler like this.t allows you to pass a data map to the event object that automatically gets fed back to the event handler function by jQuery as the first parameter. The data map would be handed to the .click() function as the first parameter, followed by the event handler function.
$(document).ready(function() {
function test(e){
alert(e.data.param1); // returns "a"
alert(e.data.param2); // returns "b"
}
$("#register").click({param1 : "a" , param2 : "b"} , test);
});
More you want about event Handler Stack Overflow
The problem is in your click event handler. This is what you have:
$("#register").click(test("a","b"));
Here you are immediately executing the test("a","b") function. Instead you want to pass in a function that calls this. Therefore the corrected code is
$("#register").click(function (){
test("a","b");
});

Where are the arguments to the jQueryUI Dialog submit handler coming from?

Take a look at the following code:
this.dialog({
width: 500,
height: 260,
title: "Setup database",
content: $("<form>").append(table),
buttons: {
submit: function(_alert, dialog) {
dialog.find("form").each(function() {
var arr = $(this).serializeArray();
var data = {
mysql: true
};
var empty = false;
$(this).find("input").removeClass("error");
for (var k in arr) {
if ($.trim(arr[k].value) !== "") {
data[arr[k].name] = arr[k].value;
} else {
empty = true;
$(this).find("input[name='" + arr[k].name + "']").each(function() {
$(this).addClass("error");
});
break;
}
}
if (!empty) {
self.ajax({
url: url,
data: data
}, function(result) {
callback(result);
}, function() {
self.mysql(url, callback, _db_name, _db_user, _db_pass, is_dialog);
});
}
_alert.remove();
if($.isFunction(callback_submit)) {
callback_submit();
}
});
}
}
});
There are two parameters passed into the anonymous function that is supposed to trigger when the button "submit" is clicked. But I have no idea where these parameters are supposed to come from. Can someone explain? Is this related to passing parameters to an anonymous function in Javascript in general?
I don't think you get any argument passed to you when a button event callback is fired on jquery-ui dialog box
http://jsfiddle.net/3d7QC/1577/
buttons: {
"I've read and understand this": function() {
console.log(arguments);
// look at your console
$(this).dialog("close");
}
Only argument you get passed through to you is the customary jQuery event object.
There should only be one parameter passed to submit, which is the event object of the button itself, when clicked. So the context set is the submit button, if you need to access the dialog and modify it, you can do so by accessing the event.target property.
this.dialog({
buttons: {
submit: function(event) {
$(event).dialog('close'); //is the same as...
$(this).dialog('close');
}
});
The first argument _alert is the JS event object that is passed to every event handler in JavaScript. This is not specific to jQuery. javascript.info explains this as follows:
W3C way
Browsers which follow W3C standards always pass the event object as
the first argument for the handler.
For instance:
element.onclick = function(event) {
// process data from event
}
In the jQueryUI API reference they confirm that i
Specifies which buttons should be displayed on the dialog. The context
of the callback is the dialog element; if you need access to the
button, it is available as the target of the event object.
I illustrated this in a fiddle. Not sure what the second argument (dialog in your case) does, though. It's not passed in my example code.

Disabling click event handlers

I am trying to basically disable the click event on a <div> temporarily.
I have tried the following (preview):
$('hello').observe('click', function (e) {
e.stop();
});
$('hello').observe('click', function (e) {
alert('click not stopped!');
});
However, when #hello is clicked, the alert box still appears. I do not want the second attached handler to be called, and I do not want to change the second handler.
I will also accept a solution such as:
$('hello').observe('click', function (e) {
alert('click not stopped!');
});
$('hello').disableEvent('click');
// Now, handler won't be called
$('hello').observe('click', function (e) {
alert('click not stopped (2)!');
});
// New handler won't be called, either
$('hello').enableEvent('click');
// Now, handler will be called
I am using the Prototype.js framework. This doesn't seem to be a browser-specific issue.
When you assign handlers to events; you are basically just storing a set of functions to be executed when an event fires.
When an event fires, the handlers you've added are executed in the order they we're added. So if you we're to add three handlers to a div's click-event:
$("div").observe("click", function ()
{
alert("one");
});
$("div").observe("click", function ()
{
alert("two");
});
$("div").observe("click", function ()
{
alert("three");
});
.. you would get three alerts ("one", "two" and "three") when the click event of the div element fires. Those three alerts will still get shown, if you put in:
$("div").observe("click", function (e)
{
e.stop();
})
.. because you are only canceling the event for one particular handler. Not all associated handlers.
So what you will need to do is use a reference variable, which keeps track of wether the click event is allowed to fire:
var cancelClickEvent = true;
$("div").observe("click", function ()
{
// if cancelClickEvent is true, return the function early, to
// stop the code underneath from getting executed
if (cancelClickEvent) return;
// your code goes here
});
You will then need to implement the above if-clause in all your handlers.
Can't you just set the object's disabled property to true?
As I said in comments to roosteronacid's answer, I wrote an extension to Event.observe. Works in most browsers, but not IE.
// XXX HACK XXX
(function () {
var handlerCache = $A([ ]);
function findHandler(either) {
var pair = handlerCache.find(function (pair) {
return $A(pair).member(either);
});
return pair && pair[0];
}
function addHandler(handler) {
function newHandler(e) {
if (!e.halted) {
handler.apply(this, arguments);
}
}
handlerCache.push([ handler, newHandler ]);
return newHandler;
}
Event.observe = Event.observe.extended(function ($super, element, eventName, handler) {
handler = findHandler(handler) || addHandler(handler);
$super(element, eventName, handler);
});
Event.stopObserving = Event.stopObserving.extended(function ($super, element, eventName, handler) {
handler = findHandler(handler) || handler;
$super(element, eventName, handler);
});
Element.addMethods({
observe: Event.observe
});
Event.prototype.halt = function () {
this.halted = true;
};
}());
Note: Function.prototype.extended is a custom function which puts the original Event.observe in as $super.

Categories

Resources