When I bind event like this:
Selector.prototype.setupEventHandlers = function() {
var cssSelector = '*:not(.' + this.ignoreClass + ')';
jQuery(cssSelector).bind("mousedown", { 'self': this }, this.onSelectorMousedown);
};
And make EventHandler like that:
Selector.prototype.onSelectorMousedown = function(e) {
self = this;
...
}
I always have self = HTMLParagraphElement instead of element that really was clicked.
Related
I have button that creates a div on click. I want to return this created div when I click a button. But the following code actually returns this button.
var create = $('#create').on('click', function(e){
var content = $('<div class="foo"/>')
return content
})
var test = create.trigger('click')
console.log(test)
Result is:
init [div#create, context: document, selector: '#create']
Is this not possible to do this this way or am I missing something?
No, it is not possible. You can add a function which will be executed in your event handler to do something with the object you create in the listener:
var create = $('#create').on('click', function(e){
var content = $('<div class="foo"/>')
doSomething(content)
})
create.trigger('click')
function doSomething(test) {
console.log(test)
}
There is no other way and it is because the handler function assigned with .on() method is called when the browser triggers an event (or you use .trigger() method) and the return statement is used only to force calling event.stopPropagation() and event.preventDefault() methods (you have to return false in the handler or just assign false instead of a function as an event handler - check the documentation, section The event handler and its environment) and not to return any value when you trigger an event manually.
You can also use an external variable to store the data "generated" in your event handler:
const divs = []
var create = $('#create').on('click', function(e){
var content = $('<div class="foo"/>')
divs.push(content)
doSomething()
})
create.trigger('click')
function doSomething() {
console.dir(divs)
}
You're calling a variable ("create") which stores the event listener on the button. This is what it looks like:
var test = $('#create').on('click', function(e){
var content = $('<div class="foo"/>')
return content
}).trigger('click')
console.log(test)
This is the solution:
jQuery
var create = function() {
return $('<div class="foo"/>');
};
var createEl = $('#create');
createEl.on('click', function() {
console.log(create());
// <div class="foo"></div>
});
createEl.trigger("click");
JavaScript
var create = function() {
var el = document.createElement('div');
el.className = "foo";
// Add other attributes if you'd like
return el;
};
var createEl = document.querySelector('#create');
createEl.addEventListener("click", function() {
console.log(create());
// <div class="foo"></div>
});
createEl.click();
(jQuery) Live example
var create = function() {
return $('<div class="foo"/>');
};
var createEl = $('#create');
createEl.on('click', function() {
console.log(create());
// <div class="foo"></div>
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<button id="create">Create</button>
(JavaScript) Live example
var create = function() {
var el = document.createElement('div');
el.className = "foo";
// Add other attributes if you'd like
return el;
};
var createEl = document.querySelector('#create');
createEl.addEventListener("click", function() {
console.log(create());
// <div class="foo"></div>
});
createEl.trigger("click");
var create = function() {
var el = document.createElement('div');
el.className = "foo";
// Add other attributes if you'd like
return el;
};
var createEl = document.querySelector('#create');
createEl.addEventListener("click", function() {
console.log(create());
// <div class="foo"></div>
});
<button id="create">Create</button>
I want to know how to add a custom event to a instance of a class and call it for that instance.
My code right now:
var event = document.createEvent('event');
event.initEvent('build', true, true);
class link {
constructor(Href, Text = "Click me", Target = "__blank") {
this.href = Href;
this.text = Text
this.target = Target;
this.eventElm = document.createElement("event");
//this.event = document.createEvent('event');
//this.event.initEvent('build', true, true);
}
}
class creator {
constructor(Objs) {
for(var i in Objs) {
window.document.body.innerHTML += ""+Objs[i].text+"<br>";
if(Objs[i].href == "#") {
Objs[i].eventElm.dispatchEvent(event);
}
}
}
}
var l = new link("#");
var lo = new link("#");
var ar = [];
ar.push(l);
ar.push(lo);
l.eventElm.addEventListener('build', function(e) {
console.log(e);
}, false);
//l.eventElm.dispatchEvent(event);
window.onload = function () {
var crea = new creator(ar);
console.log(l.href);
}
This code returns the error
eventtest.html:24 Uncaught DOMException: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.
at new creator (http://localhost/eventtest.html:24:25)
at window.onload (http://localhost/eventtest.html:44:16)
I want to do this in plain javascript no jquery. Thanks for taking the time to read this and hopefully help me.
You're declaring a global event variable. But most browsers (IE, Edge, Chrome) already have a global event variable (the currently-being-dispatched event). So you end up trying to re-dispatch the load event that's being handled.
This is one of the many reasons not to put your code at global scope. Instead, wrap it in a scoping function:
(function() {
// Your code here...
})();
Now, your event variable isn't conflicting with the global event.
Live Example:
(function() {
var event = document.createEvent('event');
event.initEvent('build', true, true);
class link {
constructor(Href, Text = "Click me", Target = "__blank") {
this.href = Href;
this.text = Text
this.target = Target;
this.eventElm = document.createElement("event");
//this.event = document.createEvent('event');
//this.event.initEvent('build', true, true);
}
}
class creator {
constructor(Objs) {
for(var i in Objs) {
window.document.body.innerHTML += ""+Objs[i].text+"<br>";
if(Objs[i].href == "#") {
Objs[i].eventElm.dispatchEvent(event);
}
}
}
}
var l = new link("#");
var lo = new link("#");
var ar = [];
ar.push(l);
ar.push(lo);
l.eventElm.addEventListener('build', function(e) {
console.log(e);
}, false);
//l.eventElm.dispatchEvent(event);
window.onload = function () {
var crea = new creator(ar);
console.log(l.href);
}
})();
Separately: You probably want to create a new event object each time you dispatch your event, rather than having that single global-to-your-code event variable.
// The parent class
var Parent = function (jqueryElement) {
this.jqueryElement = jqueryElement;
};
Parent.prototype.attachClick = function () {
var that = this;
this.jqueryElement.click(function (e) {
e.preventDefault();
that.doClick($(this));
});
}
Parent.prototype.doClick = function ($element) {
console.info('click event from parent');
}
// First child class
var A = function(jqueryElement) {
var that = this;
Parent.call(this, jqueryElement);
// this is supposed to override the Parent's
this.doClick = function ($element) {
console.info('click event from A');
};
};
A.prototype = Object.create(Parent.prototype);
var test = new A($('.selector'));
test.attachClick();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="selector">Click me</button>
At this stage, I'm supposed to see the message "click event from A", but the weird thing is that I don't see any message as if the doClick method is never executed.
How do I override an inherited method (doClick) in the child class?
You forgot to execute a click. Your code is working. =)
I will only suggest to put your .doClick() method in A.prototype, so it will be shared by all A instances.
// The parent class
var Parent = function (jqueryElement) {
this.jqueryElement = jqueryElement;
};
Parent.prototype.attachClick = function () {
var that = this;
this.jqueryElement.click(function (e) {
e.preventDefault();
that.doClick($(this));
});
}
Parent.prototype.doClick = function ($element) {
console.info('click event from parent');
}
// First child class
var A = function(jqueryElement) {
var that = this;
Parent.call(this, jqueryElement);
};
A.prototype = Object.create(Parent.prototype);
// this is supposed to override the Parent's
A.prototype.doClick = function ($element) {
console.info('click event from A');
};
var test = new A($('.selector'));
test.attachClick();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="selector">Click me</button>
https://jsfiddle.net/ekw6vk43/
I have been writing a plugin, and i really like this format
Function.prototype._onClick = function() {
// do something
}
Fuction.prototype.addListner = function() {
this.$element.on('click', this._onClick.bind(this));
}
the problem is sometimes i need the element being clicked and the main object. Doing as below i loose the dom element and not using bind looses the main object.
Fuction.prototype.addListner {
this.$element.find('.some-class').on('click', this._onClick.bind(this));
}
To achieve that i go back to ugly version
Fuction.prototype.addListner = function() {
var self = this;
this.$element.find('.some-class').on('click', function() {
self._onClick($(this));
});
}
Is there any better way to do this?
As zerkms, you can use the event.target to achieve what you want.
When using .on, the handler is :
handler
Type: Function( Event eventObject [, Anything extraParameter ] [, ...
] ) A function to execute when the event is triggered. The value false
is also allowed as a shorthand for a function that simply does return
false.
So your _onClick function will receive click event as its 1st parameter, then from event.target, you can now get the clicked item.
var Test = function(sel) {
this.$element = $(sel);
this.value = 'My value is ' + this.$element.data('val');
};
Test.prototype.addListner = function() {
this.$element.find('.some-class').on('click', this._onClick.bind(this));
}
Test.prototype._onClick = function(evt) {
// Get the target which is being clicked.
var $taget = $(evt.target);
//
console.log(this.value);
// use $target to get the clicke item.
console.log($taget.data('val'));
}
var test = new Test('#test');
test.addListner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="test" data-val="divVal">
<button class="some-class" data-val="Button-A">btnA</button>
<button class="some-class" data-val="Button-B">btnB</button>
</div>
I'm trying to remove event listeners from elements after they've been clicked on and although I seem to have a working solution, it's not ideal and I'm not sure why it works differently to the broken code.
Although I realise there are simpler ways of doing this, this is taken from a JS class I'm working on so need to retain some of the structure.
This relates to a previous post I made which was answered correctly (but didn't work when I expanded the example) - Removing event listeners with anonymous function calls in JavaScript.
In this example, the last created div removes the listener correctly but earlier ones don't (fiddle here - http://jsfiddle.net/richwilliamsuk/NEmbd/):
var ctnr = document.getElementById('ctnr');
var listener = null;
function removeDiv (d) {
alert('testing');
d.removeEventListener('click', listener, false);
}
function addDiv () {
var div = document.createElement('div');
div.innerHTML = 'test';
ctnr.appendChild(div);
div.addEventListener('click', (function (d) { return listener = function () { removeDiv(d); } })(div), false);
}
addDiv();
addDiv();
addDiv();
In the version I got working I create an array which holds all the listeners (fiddle here - http://jsfiddle.net/richwilliamsuk/3zZRj/):
var ctnr = document.getElementById('ctnr');
var listeners = [];
function removeDiv(d) {
alert('testing');
d.removeEventListener('click', listeners[d.id], false);
}
function addDiv() {
var div = document.createElement('div');
div.innerHTML = 'test';
ctnr.appendChild(div);
div.id = listeners.length;
div.addEventListener('click', (function(d) {
return listeners[listeners.length] = function() {
removeDiv(d);
}
})(div), false);
}
addDiv();
addDiv();
addDiv();
document.getElementById('btn').addEventListener('click', function() {
alert(listeners);
}, false);
The final one works fine but I'm sure the listener array shouldn't be necessary. Maybe I'm worrying too much but I'd like to know the optimal solution.
you are right, you don't need an array, just hold every listener in a variable, than pass eventlistener in your remove() function,
var ctnr = document.getElementById('ctnr');
function removeDiv(d, ev) {
alert('testing');
d.removeEventListener('click', ev, false);
}
function addDiv() {
var div = document.createElement('div');
div.innerHTML = 'test';
ctnr.appendChild(div);
div.addEventListener('click', (function(d) {
var myfunc;
return myfunc = function() {
removeDiv(d, myfunc);
}
})(div), false);
}
addDiv();
addDiv();
addDiv();
document.getElementById('btn').addEventListener('click', function() {
alert(listeners);
}, false);
updated jsfiddle page
You have to save each and every listener if they are unequal, so you need a relation between listener and element. Since an element is represented by an object (DOM: document object model) you can add custom properties to them (although it's not recommended: Can I add arbitrary properties to DOM objects?) (demo):
var ctnr = document.getElementById('ctnr');
function removeDiv (d) {
alert('testing');
d.removeEventListener('click', d.custom_Listener , false);
}
function addDiv () {
var div = document.createElement('div');
div.innerHTML = 'test';
div.custom_Listener = function(){removeDiv(this)};
ctnr.appendChild(div);
div.addEventListener('click', div.custom_Listener , false);
}
But since your using the same listener in every div its even better not to use a separate function for every div but the same (demo):
var ctnr = document.getElementById('ctnr');
var listener = function(){
removeDiv(this);
};
function removeDiv (d) {
alert('testing');
d.style.backgroundColor = '#36f';
d.removeEventListener('click', listener, false);
}
function addDiv () {
var div = document.createElement('div');
div.innerHTML = 'test';
ctnr.appendChild(div);
div.addEventListener('click', listener , false);
}