How to remove event listeners in Aurelia? - aurelia

How to remove event listeners in Aurelia?
This doesn’t appear to do anything:
detached(){
window.removeEventListener('scroll', this.windowScroll);
}
The event is still firing when i change routes.
I am attaching it in the constructor() in my view-model file:
window.addEventListener('scroll', this.windowScroll.bind(this));
I also tried deactivate() and neither are firing when I change routes.

There is at least one, but maybe two issues here.
Setting up an event listener
If you can't use the Aurelia binding for event delegation (for which scroll may or may not be a case, I haven't tried it), then you should use the attached lifecycle callback to set up your event handlers, not the constructor. The reason being that, unless you specify your view model is transient, the constructor will be called once. Instead, you really want Aurelia to turn on your event handlers every time it is attached.
attached = () => {
window.addEventListener('scroll', this.onScroll);
}
How to write a lifecycle callback
In general you should write your lifecycle callbacks using the arrow notation. This is because, IIRC, your this may get reassigned during the activation lifecycle. The arrow notation in TypeScript/ES6 will preserve your this lexically, i.e., it is what you expect it to be.
detached = () => {
window.removeEventListener('scroll', this.onScroll);
}

It's worth noting that you need to define your bindable function up in the constructor if you want to unbind it again on detach:
export MyClass {
constructor() {
this.handleBodyClick = e => {
console.log(e.target);
};
}
attached() {
document.addEventListener('click', this.handleBodyClick);
}
detached() {
document.removeEventListener('click', this.handleBodyClick);
}
Taken directly from this excellent post: http://ilikekillnerds.com/2016/02/using-event-listeners-in-aurelia/

Related

Programatically assign handler for native event in Vue JS?

I am trying to leverage a Vue mixin to add behavior when a native event happens. Using a mixin will allow me to share that across several components. Specifically, when a field component (or button, or checkbox, etc.) has focus, and the Escape key is pressed, the field loses focus.
A similar Stack Overflow question seemed to indicate I could listen for native events (see code comment about multiple events).
However, the Vue Documentation for programmatically adding an event listener using $on says that it will
Listen for a custom event on the current vm...
(Emphasis added)
Unsure if the custom event remark is absolute or based on the context, I have been experimenting. I have been trying to listen for the native keyup event (using the Vue alias keyup.esc) but have had no success. So I am wondering if it is indeed limited to custom events, and if so, why?
You can see my experiment in a code sandbox. The custom event works, the native does not.
The mixin looks like so:
// escape.mixin.js
export default {
created() {
// Custom event
this.$on("custom-event", function() {
console.log("Custom event handled by mixin");
});
// Native event
this.$on(["keyup.esc", "click"], function() {
alert("Native event handled!");
});
}
};
The main point of all this is to be able to add the behavior to a set of components by adding to how the event is handled, without overriding behavior that might also exist on the component. The secondary goal is to provide the behavior by simply adding the mixin, and not having to do component level wiring of events.
So a component script would look something like this:
// VText component
import escapeMixin from "./escape.mixin";
export default {
name: "VText",
mixins: [escapeMixin],
methods: {
onFocus() {
console.log("Has Focus");
this.$emit("custom-event");
}
}
};
Also, I was trying to avoid attaching the listener to the <input> element directly with vanilla JS because the Vue documentation suggested that letting Vue handle this was a good idea:
[When using v-on...] When a ViewModel is destroyed, all event listeners are automatically removed. You don’t need to worry about cleaning it up yourself.
Solution
skirtle's solution in the comment below did the trick. You can see it working in a code sandbox.
Or here's the relevant mixin:
export default {
mounted() {
this.$el.addEventListener("keyup", escapeBlur);
},
beforeDestroy() {
this.$el.removeEventListener("keyup", escapeBlur);
}
};
function escapeBlur(e) {
if (e.keyCode === 27) {
e.target.blur();
console.log("Lost focus");
}
}

Why is "event" accessible in Vue v-on methods even without the argument?

According to the page on event handling in the docs for Vue, when you use v-on like v-on:click="handler" the handler function will automatically get the original DOM event as the first argument. This code snippet is directly adapted from those docs.
new Vue({
// Vue config shortened for brevity
methods: {
handler(event) {
// `this` inside methods points to the Vue instance
alert('Hello ' + this.name + '!')
// `event` is the native DOM event
if (event) {
alert(event.target.tagName)
}
}
}
})
Why the heck can I still access event even if I omit it from the functions parameter list like this:
handler() {
console.log(event); // Still returns the native DOM object even though
// I don't explicitly define `event` anywhere
}
Shouldn't event be undefined if I don't add it as an argument to the function?
I believe that'll be the global window.event:
https://developer.mozilla.org/en-US/docs/Web/API/Window/event
Nothing to do with Vue, it's just an unfortunate coincidence that you happened to call it event.
Maybe the docs explains the reason to use event in the handler function as first argument:
You should avoid using this property in new code, and should instead use the Event passed into the event handler function.
https://developer.mozilla.org/en-US/docs/Web/API/Window/event

"nativeOn" vs. "on" in the render function & JSX

In the Vue documentation at https://v2.vuejs.org/v2/guide/render-function.html#The-Data-Object-In-Depth there is an explanation for “on” and “nativeOn”:
// Event handlers are nested under `on`, though
// modifiers such as in `v-on:keyup.enter` are not
// supported. You'll have to manually check the
// keyCode in the handler instead.
on: {
click: this.clickHandler
},
// For components only. Allows you to listen to
// native events, rather than events emitted from
// the component using `vm.$emit`.
nativeOn: {
click: this.nativeClickHandler
},
We are trying to listen to an “input” event from a custom component we created. We noticed that the event did not get detected in the on property, so we tried nativeOn and we were surprised to find that this worked. We were surprised because the docs say nativeOn:
Allows you to listen to
// native events, rather than events emitted from
// the component using vm.$emit
In this case, we are using an event emitted from a (custom) component using vm.$emit.
Here is a snippet from our code demonstrating the above:
on: {
input: (event) => {
console.log('hi'); // We did not receive "hi" in the console
}
},
nativeOn: {
input: (event) => {
console.log('hi2'); // We did receive "hi2" in the console
}
Any clarification on why we would need nativeOn to listen to “input” events from a custom component, or on when to use nativeOn vs. on and the differences therein would be most appreciated. Thanks in advance!

access methods from the vue current component

Can any one guide or suggest how to resolve this below issue.
Use Case: Trying to implement notification component
Scenario: I am trying to call a method or change the state of the data on triggering of event in Vue.
I have defined the event listener on mounted function and trying to access one of the method.
Basically, the alert within event function is getting triggered, where as alert inside method is not getting triggered, and even any data manipulation is not executing even with in event function.
Where am i missing? is it incorrect to alter state within Event listener?
Basically i am trying to implement notification feature which automatically disappear after few seconds
Any help is appreciated.
Thanks,
Girish
There is another reason,this inside callback function is not Vue component. You can assign var self = this and use inside the callback, or use arrow function.
mounted: function () {
var self = this
EventBus.$on('show', function () {
self.test()
self.show = true
})
},
methods: {
test () {
console.log('Inside methods')
}
}
I believe your problem is the spelling error instead of
method: {}
, use methods: {}
Example:
Error.
method: {
test: function () {
alert('Inside Method');
}
correct.
methods: {
test: function () {
alert('inside method);
}
}
I know it does not have much to do with the question, but be careful when using the event bus, it would be as if you had a speaker, and shouted in the middle of a crowd the name of a person.
Example:
eventbus says Hamilton in the midst of a crowd of 10,000 people.
How many Hamiltons can you have in the middle of this crowd? Use something more specific, such as parent-child communication, avoid using the event bus.

Jquery .off vs dojo?

What is equivalent of jquery $.off(event) to remove event on element by passing event name in Dojo?
I tried :
dojo.disconnect(handle) // but I dont have an handle to event
How to get the handle or is there any better way to to it?
There is no out of the box solution as far as I know of, so you would have to implement one by yourself. However, this could be a dangerous feature, if you suddenly disconnect all event handlers of a specific type.
However, you could use the dojo/aspect module to intercept calls to the dojo/on module, for example:
aspect.around(arguments, 0, function(original) {
on.signals = [ ];
return function(dom, name, handler) {
console.log(arguments);
on.signals.push({
signal: original.apply(this, arguments),
name: name
});
};
}, true);
I didn't find a proper way to put an aspect around a function itself, rather than a function wrapped inside an object. So I used a dirty trick and used the arguments array and because the on module is my first argument, this will put an aspect around the dojo/on reference.
What happens is that when you bind an event handler using dojo/on, it will save it inside an array. Now you could write your own dojo/on::off() function, for example:
on.off = function(eventName) {
arrayUtils.forEach(on.signals, function(signal) {
if (signal.name === eventName) {
signal.signal.remove();
}
});
};
Now you can use:
on.off("click");
To disconnect all click event handlers.
A full example can be found on JSFiddle: http://jsfiddle.net/Lj5yG/ but this could probably be improved.