Having issue with click events/memory leak - javascript

I have following JavaScript code.
var Foo = function () {
$('body').on('click', '.btn', this.update.bind(this));
};
Foo.prototype = (function () {
var update = function (e) {
console.log('update');
e.preventDefault();
};
return {
update: update
}
})();
new Foo();
new Foo();
new Foo();
I am creating 3 instances of Foo constructor. Inside constructor, I am attaching a click event to dom element. However, with this approach the click event is attached 3 times because I am creating 3 instance using new operator. How can I make this work so that after creating 3 instance it only attach one click event to that dom element?
JSFIDDLE

var Foo = function () {
$('body').off('click', '.btn');
$('body').on('click', '.btn', this.update.bind(this));
};
This removes the click event listener, then rebinds it. That way it is limited to one listener.

This is not a memory leak. This is how jQuery works if you bind events multiple times. If you do something like that:
$('body').on('click', '.btn', function(e){/*logic here*/});
$('body').on('click', '.btn', function(e){/*logic here*/});
$('body').on('click', '.btn', function(e){/*logic here*/});
It will attach the event 3 times. Why do you think that if you put this thing into a class and instantiate the class 3 times it will not attach the event.
A way to prevent this behaviour is to do something like that:
var Foo = function () {
if(!Foo.instantiatedOnce) {
$('body').on('click', '.btn', this.update.bind(this));
}
Foo.instantiatedOnce = true;
};
Foo.prototype = (function () {
var update = function (e) {
console.log('update');
e.preventDefault();
};
return {
update: update
}
})();
Foo.instantiatedOnce = false;
new Foo();
new Foo();
new Foo();
Doing something like that it is like simulating a static variable that is shared between instances.

This should work:
var binded = false;
var Foo = function () {
if (!binded) {
$('body').one('click', '.btn', this.update.bind(this));
binded = true;
}
};

Related

object oriented jquery - event handlers not working

I am moving some jquery functions into a javascript object to clean up some code. My problem is, when I put methods on my object's constructor, my event handlers don't seem to respond to events but respond fine if my handlers are helper methods and are outside of the object's constructor.
Here's my code that isn't working
function MyConstructor() {
this.init();
this.selectAllHandler();
}
MyConstructor.prototype = {
init: function() {
$(document).on('click', '#my_element', this.selectAllHandler);
},
selectAllHandler: function() {
// some code in here
}
}
When using this, my code does not error out and putting console.log's atop the function runs. But when I try to click on the thing to trigger the handler, it doesn't do anything.
But, if I build it as a constructor using a method outside of the object, it works fine. Like this
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
$(document).on('click', '#my_element', selectAllHandler);
}
}
function selectAllHandler() {
// code that works fine
}
what am I doing wrong that I cannot call the handlers inside the object's prototype?
edit
Here is my new code. The problem now, is $(this) seems to refer to the constructor and no longer refers to the element being clicked on.
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
$(document).on('click', '#my_element', this.selectAllHandler.bind(this));
},
selectAllHandler: function() {
var checkboxes = $('.prospect_select_box');
console.log($(this)); // => [MyConstructor]
if (!$(this).prop('checked')) {
console.log('here')
checkboxes.prop('checked', false);
$('#prospect-left-section').hide();
} else {
console.log('other here')
checkboxes.prop('checked', true);
$('#prospect-left-section').show();
}
}
}
You have two objects you are interested in: the constructed object, and the clicked element. The first you need to find the method selectAllHandler, the second to work with $(this) within that function. Obviously both of them cannot be this at the same time, so you'll need to reference one of them in a different way.
Here is how you could do that.
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
var that = this;
$(document).on('click', '#my_element', function () {
that.selectAllHandler.call(this);
});
},
selectAllHandler: function() {
$(this).text('clicked!');
}
}
new MyConstructor();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="my_element">click me</button>
Note how call is used to make sure the selectAllHandler will run with this set to what jQuery passed on as element.
If however, you need to also reference the constructed object with this inside setAllHandler, then do it the other way around, and use that as this, but reference the clicked element via the event object that is passed to the function:
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
var that = this;
$(document).on('click', '#my_element', this.selectAllHandler.bind(this));
},
selectAllHandler: function(e) {
var elem = e.target;
$(elem).text('clicked ' + this.other);
},
other: 'me!'
}
new MyConstructor();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="my_element">click me</button>

JavaScript: using THIS inside object function and binding event

I have an Object and I want to bind a function to a button when Object was initialized.
var MyClass = {
Click: function() {
var a = MyClass; // <---------------------- look here
a.Start();
},
Bind: function() {
var a = document.getElementById('MyButton');
a.addEventListener('click', this.Click, false); //<---------- and here
},
Init: function() {
this.Bind();
}
}
So, I'm new at using it and I don't know if object can be declared like this (inside Click() function that should be done after clicking a button):
Is it a bad practise? Which could be the best way in this case when adding an event here?
Edit: fiddle
Firstly you have a syntax error. getElementsById() should be getElementById() - no s. Once you fix that, what you have will work, however note that it's not really a class but an object.
If you did want to create this as a class to maintain scope of the contained methods and variables, and also create new instances, you can do it like this:
var MyClass = function() {
var _this = this;
_this.click = function() {
_this.start();
};
_this.start = function() {
console.log('Start...');
}
_this.bind = function() {
var a = document.getElementById('MyButton');
a.addEventListener('click', this.click, false);
};
_this.init = function() {
_this.bind();
};
return _this;
}
new MyClass().init();
<button id="MyButton">Click me</button>
For event listeners it's easiest and best to use jQuery, for example if you want to have some .js code executed when user clicks on a button, you could use:
https://api.jquery.com/click/
I don't know how new you are to .js, but you should look up to codecademy tutorials on JavaScript and jQuery.
.click() demo:
https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_event_click

Unbinding a single event from within a prototype structure

I am trying to unbind an event handler that has been added to an object's prototype. The (cut-down) code in question is:
MyClass.prototype.bindEvents = function() {
var thisObj = this;
this.$tabs.on("click", function(e) {
return thisObj.handleTabClick($(this), e);
});
}
MyClass.prototype.unbindEvents = function() {
this.$tabs.off("click", this.handleTabClick);
}
MyClass.prototype.handleTabClick = function($tab, e) {
// do something
}
I know that I can (and did) complete clear the click event by doing
this.$tabs.off("click");
but there is another event handler on there which I wish to keep.
How do I unbind a single event within the prototype structure?
You can add a namespace to the event when you create it which you can then specifically reference when you remove the event handler. try this:
MyClass.prototype.bindEvents = function() {
var thisObj = this;
this.$tabs.on("click.foo", function(e) {
return thisObj.handleTabClick($(this), e);
});
}
MyClass.prototype.unbindEvents = function() {
this.$tabs.off("click.foo");
}
For more information see the 'Event names and namespaces' section of http://api.jquery.com/on/
Also note that your method of passing the click handler through an anonymous function to the handleTabClick function is redundant, you can simply do this:
this.$tabs.on("click.foo", thisObj.handleTabClick);
MyClass.prototype.handleTabClick = function(e) {
var $tab = $(this);
// do something
}

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>

calling a function before onclick script

click me
Hello, I need to called a function before calling the onclick script when the is clicked.
I tried:
var script = $("a").attr("onclick");
$("a").attr("onclick", "");
$("a").click(function(event) {
// call bar() first, then foo();
bar();
// script is a string on Chrome
// foo() may use this, so can not globalEval.
});
how to call the script? Can I get the onclick as jQuery function? so that:
onclickFunction.call(this);
Thanks.
If you must follow this way try this:
JS:
(function() {
var a = document.getElementsByTagName('a')[0];
var foo = a.onclick;
function bar() { console.log('bar'); }
a.onclick = function() {
bar();
foo();
};
})();
jsfiddle
can't you wrap them inside another function like this? :
click me
var handler = function() {
foo(); // 1. calling foo first
bar(); // 2. calling bar second
};
You can add "mouse up" or "mouse down" event to the element, this event will call before the "click" event call. Here is the demo.
void function(){
$("div").mousedown(function(){
console.log("mouse down event")
})
$("div").mouseup(function(){
console.log("mouse up event")
})
$("div").click(function(){
console.log("click event")
})
}();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>click me</div>

Categories

Resources