Class events bind and unbind - javascript

Everyhing works fine, except I can't figure out how to unbind the events in stop().
Code updated
class Resizable {
go(drag_el, resize_el) {
this.resize_el = resize_el;
drag_el.addEventListener("mousedown", () => {
window.addEventListener("mousemove", this.resize.bind(this));
window.addEventListener("mouseup", () => {
window.removeEventListener("mousemove", this.resize.bind(this));
window.removeEventListener("mouseup", this.resize.bind(this));
});
});
}
resize(e) {
this.resize_el.style.width = e.clientX - this.resize_el.offsetLeft + "px";
}
}
A few notes
I prefer to keep the class things inside the class, no additional var outside it.
I accept ES5 and ES6 as well.
I've read that I could do window.mousemove.bind(() => { // Code }); but I don't get that to work.

For scenario as such, I usually prefer pass the object directly as listener to addEventListener: it makes everything easier IMVHO. You have just to implement the handleEvent method:
class Resizable {
// Keeping a reference to the elements it's easier for the events handling
constructor(drag_el, resize_el) {
this.drag_el = drag_el;
this.resize_el = resize_el;
// The entry point event handler is added in the constructor
// to avoid to add multiple listeners (e.g. in the original
// code we could have called `go` method multiple times).
this.drag_el.addEventListener("mousedown", () => {
// Here we add the object itself as event handler
window.addEventListener("mousemove", this);
window.addEventListener("mouseup", this);
});
}
resize(e) {
this.resize_el.style.width = e.clientX - this.resize_el.offsetLeft + "px";
}
// Here we're removing the object itself as event handler
stop() {
window.removeEventListener("mousemove", this, false);
window.removeEventListener("mouseup", this, false);
}
// Here we're handling the events: since we added the object
// itself, `this` is still pointing to our instance of `Resizable`
// so we can call its methods.
handleEvent(event) {
switch (event.type) {
case "mousemove":
this.resize(event);
break;
case "mouseup":
this.stop();
break;
}
}
}
This approach reduces the usage of bindings and arrow functions a lot.
Here you can find a codepen demo with this code running.

You can't remove listeners inside stop function because you don't know them references.
Mousemove event don't call resize function, it call anonymous function
e => {
this.resize(resize_el, e);
}
You can save address of anonymous function in variable and use it for removing listener, like this
class Resizable {
constructor() {
this.mouseMoveHandler = (e) => {
this.resize(resize_el, e);
};
this.mouseDownHandler = () => {
window.addEventListener("mousemove", this.mouseMoveHandler);
}
this.mouseUpHandler = () => {
window.removeEventListener("mousemove", this.mouseMoveHandler);
}
}
go(drag_el, resize_el) {
drag_el.addEventListener("mousedown", this.mouseDownHandler);
window.addEventListener("mouseup", this.mouseUpHandler);
}
resize(resize_el, e) {
resize_el.style.width = e.clientX - resize_el.offsetLeft + "px";
}
stop() {
window.removeEventListener("mousemove", this.mouseMoveHandler); // ?
// most likely you would like remove listeners from this.go
}
}
You can find more info in this article on Medium [removeEventListener() and anonymous function]
UPD (after question update):
.bind() create NEW function everytime, so you still can't remove event listener.
Check my fiddle here: https://jsfiddle.net/nvfcq80z/5/

somehow what saveli said is true you have to call same function reference(pointing to same function called inside the listener) when removing listener ,if you wanna far more explaining ask sure you can ask
class Resizable {
go(drag_el, resize_el) {
this.resize_el=resize_el;
drag_el.addEventListener("mousedown", () => {
$(window).bind("mousemove", this.resize);
$(window).bind("mouseup", this.stop);
});
}
resize= (e) =>{
this.resize_el.style.width = e.clientX - this.resize_el.offsetLeft + "px";;
}
stop =(event) =>{
$(window).unbind(event,this.stop);
$(window).unbind("mousemove",this.resize);
}
}
edit this one with js only no jquery
class Resizable {
go(drag_el, resize_el) {
this.resize_el=resize_el;
drag_el.addEventListener("mousedown", () => {
window.addEventListener("mousemove", this.resize);
window.addEventListener("mouseup", this.stop);
});
}
resize= (e) =>{
this.resize_el.style.width = e.clientX - this.resize_el.offsetLeft + "px";
}
stop =(event) =>{
window.removeEventListener(event,this.stop);
window.removeEventListener("mousemove",this.resize);
}
}

I have already accepted the working answer that I liked the most. However I think a combination of #SaveliTomac and #ZER0 would be the best answer.
Therefor I have picked the best from both worlds, at least in my opinion.
https://jsfiddle.net/nhLjozm7/
HTML
<aside class="sidebar1">
<div class="sidebar1-resize"></div>
</aside>
<div class="sidebar2">
<div class="sidebar2-resize"></div>
</div>
JS
class Resizable {
constructor(drag_el, resize_el) {
this.drag_el = drag_el;
this.resize_el = resize_el;
this.handlers();
this.events();
}
handlers() {
this.mouseMoveHandler = (e) => {
this.resize(this.resize_el, e);
};
this.mouseDownHandler = () => {
window.addEventListener("mousemove", this.mouseMoveHandler);
}
this.mouseUpHandler = () => {
window.removeEventListener("mousemove", this.mouseMoveHandler);
}
}
events() {
this.drag_el.addEventListener("mousedown", this.mouseDownHandler);
window.addEventListener("mouseup", this.mouseUpHandler);
}
resize(resize_el, e) {
resize_el.style.width = e.clientX - resize_el.offsetLeft + "px";
}
}
let drag1 = document.querySelector(".sidebar1-resize");
let element1 = document.querySelector(".sidebar1");
new Resizable(drag1, element1);
let drag2 = document.querySelector(".sidebar2-resize");
let element2 = document.querySelector(".sidebar2");
new Resizable(drag2, element2);
I like the more flat handlers structure by #SaveliTomac (no nesting of events).
I like how #ZER0 put the resize handle inside the aside instead of outside of it.
I like how both #ZER0 and #SaveliTomac solutions support multiple resizable areas.
I like the clean and readability code by #SaveliTomac.
I like the set of values directly into constructor by #ZER0.
I wrapped all handlers into a method.
I wrapped events into a method.
I changed the HTML a bit.
I show two resizable elements.

Related

Can not remove event listener using setTimeout on element using class method

So I have this function (App.btnInteractive) that adds or removes mouseover and mouseout event listeners according to the boolean passed into the function call
'use strict';
const btnStart = document.querySelector('.btn--start');
class App {
constructor() {
btnStart.addEventListener('click', this.start.bind(this));
}
btnInteractive(state) {
console.log(`Check: ${state}`);
function mouseover() {
console.log('over');
}
function mouseout() {
console.log('out');
}
if (state) {
btnStart.addEventListener('mouseover', mouseover);
btnStart.addEventListener('mouseout', mouseout);
} else {
btnStart.removeEventListener('mouseover', mouseover);
btnStart.removeEventListener('mouseout', mouseout);
}
}
start() {
this.btnInteractive(true);
setTimeout(() => {
this.btnInteractive(false);
}, 2000);
}
}
const app = new App();
That results in console output below after clicking button and moving cursor out of the button and on it after each function call
Check: true
out
over
Check: false
out
over
So here's my trail of thought:
Both if and else code blocks execute
Stripping the code down (resulted in code in question itself)
Removing click event listener doesn't help
Removing both click and mouseout also doesn't work
Idea is that after 2 seconds passed the mouseover and mouseout event listeners should be removed.
I'm not an expert in Javascript, but i think that when you try to remove the event listeners, you need to have the real reference to the function you used before.
When you execute it again inside the setTimeout, it is trying to remove the reference to the new functions "mouseover" and "mouseout" that were created.
Try setting the callbacks for the listeners like that:
if (state) {
btnStart.onmouseover = mouseover;
btnStart.onmouseout = mouseout;
} else {
btnStart.onmouseover = () => {};
btnStart.onmouseout = () => {};
}

Removing eventHandler in function called by addEventListener

I added an infinite scrolling feature to my page. It attaches an event listener in the componentDidMount lifecycle hook and I want to remove it within the action called by the event listener when there is no "nextlink anymore". I set a console.log() message which works fine, but I am uncertain why the window.removeEventListener() function does not work. Any help would be appreciated.
Piece of code responsible for adding/removing the eventListener.
componentDidMount() {
this._isMounted = true;
this.props.onFetchTeams();
this.scrollListener = window.addEventListener("scroll", e => {
this.handleScroll(e);
});
}
handleScroll = () => {
const hasMoreLink = this.props.teams["#odata.nextLink"];
if (hasMoreLink == "") {
console.log("remove event handler");
window.removeEventListener("scroll", this.handleScroll);
}
// If there is at least a team and is currently not loading, proceed to load more.
if (this.state.loadingMore === false && this.props.teams["value"]) {
// get the last teamcard in the page
const lastTeam = document.querySelector(
".team-card-wrapper:last-of-type"
);
// get the height of the current team, and get the height of the current position on screen.
const lastTeamOffset = lastTeam.offsetTop + lastTeam.clientHeight;
const pageOffset = window.pageYOffset + window.innerHeight;
// the range that teams will load earlier than the bottom of the page.
const bottomOffset = 30;
if (pageOffset > lastTeamOffset - bottomOffset) {
this.setState({ loadingMore: true });
this.props.onFetchMoreTeams(hasMoreLink);
}
}
};
removeListener needs the same reference for function that it used while addListener. Change the code to addEventListener like
this.scrollListener = window.addEventListener("scroll", this.handleScroll);
This is because the function that is given to addEventListener and the one given to the removeEventListener should be exactly the same, but in your case, you are creating a new arrow function for the addEventListener. so I think you should try something like this:
this.scrollListener = window.addEventListener("scroll", this.handleScroll)
...
handleScroll = (e) => {
...
if(noMoreScroll) window.removeEventListener("scroll", this.handleScroll)
...
}
I hope this helps you :)
Consider revising the way your add the scroll event handler, by passing the handleScroll function directly:
componentDidMount() {
this._isMounted = true;
this.props.onFetchTeams();
/*
With the this.handleScroll bound to this class instance, we can now pass the method
directly to addEventListener as shown
*/
this.scrollListener = window.addEventListener("scroll", this.handleScroll);
}
handleScroll = () => {
const hasMoreLink = this.props.teams["#odata.nextLink"];
if (hasMoreLink == "") {
console.log("remove event handler");
/* This will now work as expected */
window.removeEventListener("scroll", this.handleScroll);
}
/* Rest of your code remains unchanged .. */
}

Javascript ES6 addEventListener inside Class

I am learning ES6 and I don't understand why my addEventListener not working (trigger only one time) when I use a function like this :
// Trigger only one time
window.addEventListener("scroll", this.scroll() );
But when I do this :
// working !!
window.addEventListener("scroll", (e) => {
let top = window.pageYOffset;
console.log(top + " vs " + this.offsetTop)
if (top >= this.offsetTop) {
this.el.classList.add('is-sticky');
} else {
this.el.classList.remove('is-sticky');
}
});
The full code can be find here : https://codepen.io/paallaire/pen/GQLzmg/?editors=0010#0
The statement:
window.addEventListener("scroll", this.scroll() );
Binds to the event the result of this.scroll(), which is a function call. Such invocation returns undefined, because the scroll method has no return statement:
scroll() {
let top = window.pageYOffset;
console.log(top + " vs " + this.offsetTop);
if (top >= this.offsetTop) {
this.el.classList.add('is-sticky');
} else {
this.el.classList.remove('is-sticky');
}
}
Correct way
Do NOT use:
window.addEventListener("scroll", this.scroll);
The code above will bind the this to window when the event triggers.
The CORRECT way to use is really:
window.addEventListener("scroll", (e) => {
this.scroll();
});
Or
window.addEventListener("scroll", this.scroll.bind(this));
Which, when the event is triggered, will have the code inside this.scroll have the this point to the current class (Sticky) instance.
Removing the event listener
To remove the event, call window.removeEventListener, but there's a caveat: removeEventListener must be called with the exact same argument used in addEventListener to remove the listener. In other words, to be able to remove you will have to do:
// save the function that will be bound to the event, so you can remove it later
this.scrollBoundFunction = this.scroll.bind(this);
window.addEventListener("scroll", this.scrollBoundFunction);
// and later
window.removeEventListener("scroll", this.scrollBoundFunction);

how to pass self(this) to addEventListener without breaking removeEventListener?

I'm adding checkboxchange event to checkbox here. (moveButton is a checkBox because im using CSS checkbox hack)
var self = this;
this.moveButton.addEventListener("change", function(e){self.toggleMove(e, self)});
if the checkbox is checked it adds an eventListener to body.document
DR.prototype.toggleMove = function(e, self){
if(self.moveButton.checked){
document.body.addEventListener("click", function bodyEvent(e){self.removeableEventHandler(e, self)}, false);
}else{
console.log("unchecked");
document.body.removeEventListener("click", function bodyEvent(e){self.removeableEventHandler(e, self)}, false);
}
}
if i don't wrap self.removeableEventHandler in a function i am unable to attach self to the function, but when i wrap it in a function i will be unable to remove the event when the checkbox is unchecked.
DR.prototype.removeableEventHandler = function(e, self){
console.log(e.clientX, e.clientY);
self.ele.style.top = e.clientY + "px";
self.ele.style.left = e.clientX + "px";
};
So it seems to be like I'm having a bit of a scope conundrum here. Not sure how to fix it. I'm trying to make a form moveable when the checkbox is checked and then removing the move event when the checkbox is unchecked.
removeEventListener works by passing the original function reference. If you pass a copy it wont work.
You can do:
DR.prototype.toggleMove = (function () {
var boundBodyEvent;
function bodyEvent(e) {
this.removeableEventHandler(e);
}
return function (e) {
if (this.moveButton.checked) {
boundBodyEvent= bodyEvent.bind(this);
document.body.addEventListener("click", boundBodyEvent, false);
} else {
document.body.removeEventListener("click", boundBodyEvent, false);
}
};
}());
I don't think you need to pass self around, that seems strange to me. I'm using bind to override the this in bodyEvent to refernce your DR instance instead of the DOM Element.
I'm also using immediate invocation to avoid having to put the bodyEvent in the global scope.
Alternatively, you could also not bother removing the event listener and have a switch inside the event listener:
DR.prototype.init = function () {
var self = this;
document.body.addEventListener("click", function (e) {
if (self.moveButton.checked) {
self.removeableEventHandler(e);
}
}, false);
}
removeEventListener callbak function need to be reference to the same function as in addEventListener, try this:
function bodyEvent(e) {
self.removeableEventHandler(e, self);
}
DR.prototype.toggleMove = function(e, self) {
if (self.moveButton.checked) {
document.body.addEventListener("click", bodyEvent, false);
} else {
console.log("unchecked");
document.body.removeEventListener("click", bodyEvent, false);
}
};

adding multiple event listeners to one element

So my dilemma is that I don't want to write the same code twice. Once for the click event and another for the touchstart event.
Here is the original code:
document.getElementById('first').addEventListener('touchstart', function(event) {
do_something();
});
document.getElementById('first').addEventListener('click', function(event) {
do_something();
});
How can I compact this? There HAS to be a simpler way!
I thought some might find this approach useful; it could be applied to any similarly repetitive code:
ES6
['click','ontouchstart'].forEach( evt =>
element.addEventListener(evt, dosomething, false)
);
ES5
['click','ontouchstart'].forEach( function(evt) {
element.addEventListener(evt, dosomething, false);
});
You can just define a function and pass it. Anonymous functions are not special in any way, all functions can be passed around as values.
var elem = document.getElementById('first');
elem.addEventListener('touchstart', handler, false);
elem.addEventListener('click', handler, false);
function handler(event) {
do_something();
}
Maybe you can use a helper function like this:
// events and args should be of type Array
function addMultipleListeners(element,events,handler,useCapture,args){
if (!(events instanceof Array)){
throw 'addMultipleListeners: '+
'please supply an array of eventstrings '+
'(like ["click","mouseover"])';
}
//create a wrapper to be able to use additional arguments
var handlerFn = function(e){
handler.apply(this, args && args instanceof Array ? args : []);
}
for (var i=0;i<events.length;i+=1){
element.addEventListener(events[i],handlerFn,useCapture);
}
}
function handler(e) {
// do things
};
// usage
addMultipleListeners(
document.getElementById('first'),
['touchstart','click'],
handler,
false);
[Edit nov. 2020] This answer is pretty old. The way I solve this nowadays is by using an actions object where handlers are specified per event type, a data-attribute for an element to indicate which action should be executed on it and one generic document wide handler method (so event delegation).
const firstElemHandler = (elem, evt) =>
elem.textContent = `You ${evt.type === "click" ? "clicked" : "touched"}!`;
const actions = {
click: {
firstElemHandler,
},
touchstart: {
firstElemHandler,
},
mouseover: {
firstElemHandler: elem => elem.textContent = "Now ... click me!",
outerHandling: elem => {
console.clear();
console.log(`Hi from outerHandling, handle time ${
new Date().toLocaleTimeString()}`);
},
}
};
Object.keys(actions).forEach(key => document.addEventListener(key, handle));
function handle(evt) {
const origin = evt.target.closest("[data-action]");
return origin &&
actions[evt.type] &&
actions[evt.type][origin.dataset.action] &&
actions[evt.type][origin.dataset.action](origin, evt) ||
true;
}
[data-action]:hover {
cursor: pointer;
}
<div data-action="outerHandling">
<div id="first" data-action="firstElemHandler">
<b>Hover, click or tap</b>
</div>
this is handled too (on mouse over)
</div>
For large numbers of events this might help:
var element = document.getElementById("myId");
var myEvents = "click touchstart touchend".split(" ");
var handler = function (e) {
do something
};
for (var i=0, len = myEvents.length; i < len; i++) {
element.addEventListener(myEvents[i], handler, false);
}
Update 06/2017:
Now that new language features are more widely available you could simplify adding a limited list of events that share one listener.
const element = document.querySelector("#myId");
function handleEvent(e) {
// do something
}
// I prefer string.split because it makes editing the event list slightly easier
"click touchstart touchend touchmove".split(" ")
.map(name => element.addEventListener(name, handleEvent, false));
If you want to handle lots of events and have different requirements per listener you can also pass an object which most people tend to forget.
const el = document.querySelector("#myId");
const eventHandler = {
// called for each event on this element
handleEvent(evt) {
switch (evt.type) {
case "click":
case "touchstart":
// click and touchstart share click handler
this.handleClick(e);
break;
case "touchend":
this.handleTouchend(e);
break;
default:
this.handleDefault(e);
}
},
handleClick(e) {
// do something
},
handleTouchend(e) {
// do something different
},
handleDefault(e) {
console.log("unhandled event: %s", e.type);
}
}
el.addEventListener(eventHandler);
Update 05/2019:
const el = document.querySelector("#myId");
const eventHandler = {
handlers: {
click(e) {
// do something
},
touchend(e) {
// do something different
},
default(e) {
console.log("unhandled event: %s", e.type);
}
},
// called for each event on this element
handleEvent(evt) {
switch (evt.type) {
case "click":
case "touchstart":
// click and touchstart share click handler
this.handlers.click(e);
break;
case "touchend":
this.handlers.touchend(e);
break;
default:
this.handlers.default(e);
}
}
}
Object.keys(eventHandler.handlers)
.map(eventName => el.addEventListener(eventName, eventHandler))
Unless your do_something function actually does something with any given arguments, you can just pass it as the event handler.
var first = document.getElementById('first');
first.addEventListener('touchstart', do_something, false);
first.addEventListener('click', do_something, false);
Simplest solution for me was passing the code into a separate function and then calling that function in an event listener, works like a charm.
function somefunction() { ..code goes here ..}
variable.addEventListener('keyup', function() {
somefunction(); // calling function on keyup event
})
variable.addEventListener('keydown', function() {
somefunction(); //calling function on keydown event
})
I have a small solution that attaches to the prototype
EventTarget.prototype.addEventListeners = function(type, listener, options,extra) {
let arr = type;
if(typeof type == 'string'){
let sp = type.split(/[\s,;]+/);
arr = sp;
}
for(let a of arr){
this.addEventListener(a,listener,options,extra);
}
};
Allows you to give it a string or Array. The string can be separated with a space(' '), a comma(',') OR a Semicolon(';')
I just made this function (intentionally minified):
((i,e,f)=>e.forEach(o=>i.addEventListener(o,f)))(element, events, handler)
Usage:
((i,e,f)=>e.forEach(o=>i.addEventListener(o,f)))(element, ['click', 'touchstart'], (event) => {
// function body
});
The difference compared to other approaches is that the handling function is defined only once and then passed to every addEventListener.
EDIT:
Adding a non-minified version to make it more comprehensible. The minified version was meant just to be copy-pasted and used.
((element, event_names, handler) => {
event_names.forEach( (event_name) => {
element.addEventListener(event_name, handler)
})
})(element, ['click', 'touchstart'], (event) => {
// function body
});
I'm new at JavaScript coding, so forgive me if I'm wrong.
I think you can create an object and the event handlers like this:
const myEvents = {
click: clickOnce,
dblclick: clickTwice,
};
function clickOnce() {
console.log("Once");
}
function clickTwice() {
console.log("Twice");
}
Object.keys(myEvents).forEach((key) => {
const myButton = document.querySelector(".myButton")
myButton.addEventListener(key, myEvents[key]);
});
<h1 class="myButton">Button</h1>
And then click on the element.
document.getElementById('first').addEventListener('touchstart',myFunction);
document.getElementById('first').addEventListener('click',myFunction);
function myFunction(e){
e.preventDefault();e.stopPropagation()
do_something();
}
You should be using e.stopPropagation() because if not, your function will fired twice on mobile
This is my solution in which I deal with multiple events in my workflow.
let h2 = document.querySelector("h2");
function addMultipleEvents(eventsArray, targetElem, handler) {
eventsArray.map(function(event) {
targetElem.addEventListener(event, handler, false);
}
);
}
let counter = 0;
function countP() {
counter++;
h2.innerHTML = counter;
}
// magic starts over here...
addMultipleEvents(['click', 'mouseleave', 'mouseenter'], h2, countP);
<h1>MULTI EVENTS DEMO - If you click, move away or enter the mouse on the number, it counts...</h1>
<h2 style="text-align:center; font: bold 3em comic; cursor: pointer">0</h2>
What about something like this:
['focusout','keydown'].forEach( function(evt) {
self.slave.addEventListener(evt, function(event) {
// Here `this` is for the slave, i.e. `self.slave`
if ((event.type === 'keydown' && event.which === 27) || event.type === 'focusout') {
this.style.display = 'none';
this.parentNode.querySelector('.master').style.display = '';
this.parentNode.querySelector('.master').value = this.value;
console.log('out');
}
}, false);
});
// The above is replacement of:
/* self.slave.addEventListener("focusout", function(event) { })
self.slave.addEventListener("keydown", function(event) {
if (event.which === 27) { // Esc
}
})
*/
You can simply do it iterating an Object. This can work with a single or multiple elements. This is an example:
const ELEMENTS = {'click': element1, ...};
for (const [key, value] of Object.entries(ELEMENTS)) {
value.addEventListener(key, () => {
do_something();
});
}
When key is the type of event and value is the element when you are adding the event, so you can edit ELEMENTS adding your elements and the type of event.
Semi-related, but this is for initializing one unique event listener specific per element.
You can use the slider to show the values in realtime, or check the console.
On the <input> element I have a attr tag called data-whatever, so you can customize that data if you want to.
sliders = document.querySelectorAll("input");
sliders.forEach(item=> {
item.addEventListener('input', (e) => {
console.log(`${item.getAttribute("data-whatever")} is this value: ${e.target.value}`);
item.nextElementSibling.textContent = e.target.value;
});
})
.wrapper {
display: flex;
}
span {
padding-right: 30px;
margin-left: 5px;
}
* {
font-size: 12px
}
<div class="wrapper">
<input type="range" min="1" data-whatever="size" max="800" value="50" id="sliderSize">
<em>50</em>
<span>Size</span>
<br>
<input type="range" min="1" data-whatever="OriginY" max="800" value="50" id="sliderOriginY">
<em>50</em>
<span>OriginY</span>
<br>
<input type="range" min="1" data-whatever="OriginX" max="800" value="50" id="sliderOriginX">
<em>50</em>
<span>OriginX</span>
</div>
//catch volume update
var volEvents = "change,input";
var volEventsArr = volEvents.split(",");
for(var i = 0;i<volknob.length;i++) {
for(var k=0;k<volEventsArr.length;k++) {
volknob[i].addEventListener(volEventsArr[k], function() {
var cfa = document.getElementsByClassName('watch_televised');
for (var j = 0; j<cfa.length; j++) {
cfa[j].volume = this.value / 100;
}
});
}
}
'onclick' in the html works for both touch and click event. Here's the example.
This mini javascript libary (1.3 KB) can do all these things
https://github.com/Norair1997/norjs/
nor.event(["#first"], ["touchstart", "click"], [doSomething, doSomething]);

Categories

Resources