I would like to convert the event handler to a jquery style click event but it doesnt seem to like passing the event through, perhaps its because its not an anonymous function anymore?
// variables
var faqOne = document.getElementById("faqOne");
var $hiddenOne = $(".faqOneHidden");
// javascript event handler works!
faqOne.addEventListener("click", function(e){
showFaqOne.showClickedFaq(e);
}, false);
// javascript event handle - doesnt work!
$("#faqOne").click(function(){
showFaqOne.showClickedFaq(e);
});
// constructor
function DisplayQFaqs(link, faq){
this.link = link;
this.faq = faq;
}
// method prototype
DisplayQFaqs.prototype.showClickedFaq = function(e){
var el = e.currentTarget;
if(el === this.link) {
this.faq.toggle("slow", function(){
});
}
};
// new DisplayQFaqs Objects
var showFaqOne = new DisplayQFaqs(faqOne,$hiddenOne);
Your e is undefined inside
$("#faqOne").click(function(){
showFaqOne.showClickedFaq(e);
});
Change it to
$("#faqOne").click(function(e){//Now e is there
showFaqOne.showClickedFaq(e);
});
Related
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.
I'm creating a custom event in plain Javascript and attaching it to a DOM element. The element has multiple event listeners for the same event. The code I've written is:
var element = document.getElementById('demo');
element.addEventListener("myCustomEvent", function(e) {
console.log("myCustomEvent first handler triggered");
});
element.addEventListener("myCustomEvent", function(e) {
console.log("myCustomEvent second handler triggered");
e.data['otherKey'] = 'other value';
return e.data;
});
// Trigger the event
var event = new CustomEvent("myCustomEvent", {
data: {
firstKey: 'first Value'
}
});
element.dispatchEvent(event);
Now what I want is, get the data from last event handler like below:
var modifiedData = element.dispatchEvent(event);
Though I know the above line may not be correct, but I want something like that. If I use jQuery, there is pretty simple thing like $.triggerHandler I can use that iterates over all the listeners for a particular event and gives the return value of last handler if any.
But I want to do it in pure Javascript. Is there any solution for such kind of thing?
Just use the detail property and it should work just as you'd expect:
var element = document.getElementById('demo');
element.addEventListener("myCustomEvent", function(e) {
console.log("myCustomEvent first handler triggered");
e.detail.otherKey = 'second value';
});
element.addEventListener("myCustomEvent", function(e) {
console.log("myCustomEvent second handler triggered");
console.log(e.detail);
});
// Trigger the event
var event = new CustomEvent("myCustomEvent", {
detail: {
firstKey: 'first Value'
}
});
element.dispatchEvent(event);
<div id="demo"></div>
Per comments, here's an idea how you could achieve what you're hoping to do:
var element = document.getElementById('demo');
var originalFun = element.__proto__.addEventListener.bind(element);
var handlers = {};
var wrapperFun = function(e) {
if (e.type in handlers) {
var data = e.detail;
handlers[e.type].forEach(function(fun){
data = fun(data) || data;
});
}
};
element.__proto__.addEventListener = function(type, handler) {
if (typeof handlers[type] === 'undefined') {
handlers[type] = [];
originalFun(type, wrapperFun);
}
handlers[type].push(handler);
};
element.addEventListener("myCustomEvent", function(e) {
console.log("myCustomEvent first handler triggered");
e.otherKey = 'second value';
return e;
});
element.addEventListener("myCustomEvent", function(e) {
console.log("myCustomEvent second handler triggered");
console.log(e);
});
// Trigger the event
var event = new CustomEvent("myCustomEvent", {
detail: {
firstKey: 'first Value'
}
});
element.dispatchEvent(event);
<div id="demo"></div>
The easiest way is to save all Event listener results to some object.
Like const eventObj = {};
So, after each event you can just Object.assign(eventObj, <yourDataFromEvent>
More about Object.assign() here
Tell me please, why removeEvent is not working and click on body working after removeEventListener was called. I just make it more simple for good understanding
p - my object with properties and methods;
p.is_open - true/false property;
p.switcher - DOM element;
function MyClassname(){
.......
p.switcher.onclick = function(e){
if(p.is_open){
p.close();
document.body.removeEventListener('click', p.close.bind(p));
}else{
p.open();
document.body.addEventListener('click', p.close.bind(p));
};
e.stopPropagation();
};
.......
};
.......
MyClassname.prototype.close = function(){
var p = this;
p.is_open = false;
p.switcher.className = 'closed';
};
MyClassname.prototype.open = function(){
var p = this;
p.is_open = true;
p.switcher.className = 'open';
};
I can solve this task in another way, but I want to get the problem.
Thanks.
You can't remove the event listener because you have to store p.close.bind(p) in a variable.
Something like this:
function MyClassname(){
var closeHandler = p.close.bind(p);
.......
p.switcher.onclick = function(e){
if(p.is_open){
p.close();
document.body.removeEventListener('click', closeHandler);
}else{
p.open();
document.body.addEventListener('click', closeHandler);
};
e.stopPropagation();
};
.......
};
.......
MyClassname.prototype.close = function(){
var p = this;
p.is_open = false;
p.switcher.className = 'closed';
};
MyClassname.prototype.open = function(){
var p = this;
p.is_open = true;
p.switcher.className = 'open';
};
The bit p.close.bind(p) wil create a new function with the same body.
It is an entirelly new object. And comparing 2 different objects returns false.
Partially quoting MDN about the .bind() method:
The bind() method creates a new function that, when called, has its this keyword set to the provided value [...].
Here's an example:
var button = document.getElementsByTagName('button')[0];
var handler = function(){
console.log('click');
//this refers to the button
this.removeEventListener('click', handler.bind(this));
};
button.addEventListener('click', handler.bind(button));
<button>Click me</button>
As you can see, the click stays there. Here's another example:
var button = document.getElementsByTagName('button')[0];
var handler = (function(){
console.log('click');
//this refers to the button
this.removeEventListener('click', handler);
}).bind(button);
button.addEventListener('click', handler);
<button>Click me</button>
Storing the result of the .bind() inside a variable allows you to do as you wish, and you are refering to the same exact object.
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 creating a custom WinJS control with an event listener. For simplicity, this example should fire an event whenever it is tapped.
This is created with the markup:
<div class="alphaNavBar" data-win-control="MobMan.Controls.AlphaNavBar"></div>
The control is implemented here. It throws an "invalid argument" exception at the dispatchEvent(...) line.
(function () {
var alphaNavBar = WinJS.Class.define(function (el, options) {
// Create control
var self = this;
this._element = el || document.createElement("div");
this._element.winControl = this;
this._element.innerText = "Hello World!";
this._selection = false;
// Listen for tap
this._element.addEventListener("MSPointerDown", function (evt) {
// Toggle selection
self._selection = !self._selection;
// Selection changed, fire event
// Invalid argument here
self._element.dispatchEvent("mySelectionChanged", { selection: self._selection });
// Invalid argument here
});
});
// Add to global namespace
WinJS.Namespace.define("MobMan.Controls", {
AlphaNavBar: alphaNavBar
});
// Mixin event properties
WinJS.Class.mix(MobMan.Controls.AlphaNavBar, WinJS.Utilities.createEventProperties("mySelectionChanged"), WinJS.UI.DOMEventMixin);
})();
This event is listened to by:
var alphaNavBar = document.querySelector(".alphaNavBar");
alphaNavBar.addEventListener("mySelectionChanged", function (evt) {
// Should fire when alphaNavBar is tapped
debugger;
});
What am I doing wrong here?
I posted my question here as well and got an answer modifying the event dispatch like so:
// Listen for tap
this._element.addEventListener("MSPointerDown", function (evt) {
// Toggle selection
this._selection = !this._selection;
// Create the event.
var _event = document.createEvent('customevent');
// Define that the event name is 'mySelectionChanged' and pass details.
_event.initCustomEvent('mySelectionChanged', true, true, { selection: this._selection });
// Selection changed, fire event
this.dispatchEvent(_event);
});
This was able to trigger the event correctly for me. Still not sure what I was doing wrong before, but it is fixed now.