How to cancel execution of debounced function in form event? - lodash

I have a form with 2 handlers:
<form onChange={_.debounce(func, 1000)} onBlur={func} />
I used this construction to handle update of the data via websocket connection, and this solution is just what I need, but in this particular case func fires twice on blur, is there any way to cancel execution of onChange handler when onBlur is being triggered?

Ok, I've found that lodash .debounce function has two handy methods: cancel and flush which are just what I've needed.

Related

Vue 3 - Prevent event propagation on custom event handlers

If i have a custom event handler like #my-event and i emit it with
this.$emit('my-event')
it calls all the events of #my-event from all parent components.
But i want to prevent this.
On normal event handlers like #click, we can simply add .stop behind it to prevent this behaviour.
But .stop does not work on custom event listeners.
Fiddle without stop: https://jsfiddle.net/xn9sq4cp/
Fiddle with stop: https://jsfiddle.net/xy18mspz/
I know i can add
inheritAttrs: false
to prevent event propagation globaly, but i dont want this.
So, how can i prevent event propagation for custom event handlers.
Thanks.
You can stop the component from emitting the event to stop it from being bubbled up by adding this:
// ...
emits: {
'my-event': false
}
// ...
JS Fiddle

Emit keydown event with key modifier on a stub in vue-test-utils

I have a auto-stubbed child component with a keydown event with a .down modifier. I want to trigger this event in my test.
Somewhere in component.vue:
<child-component #keydown.down="myFn()" />
Somewhere in component.spec.js:
// I expect the keydown.down event to be triggered:
wrapper.find({name: 'child-component'}).vm.$emit('keydown.down')
This doesn't work. The only way I was able to trigger the event is when i remove the modifier .down, or if I add a .native modifier to the event. Unfortunately I'm unable to use the .native modifier.
Other things I've tried:
wrapper.find({name: 'child-component'}).trigger('keydown.down')
wrapper.find({name: 'child-component'}).vm.$emit('keydown', {keyCode: 40})
The solution is to supply a KeyboardEvent as the second parameter of the $emit function, with the keyCode of the key modifier. So if we want to trigger a keydown.down event, we can do so as such:
wrapper.find({name: 'child-component'}).vm.$emit(
'keydown',
new KeyboardEvent('keydown', {
keyCode: 40
})
)

Closing bootstrap vue modal doesn't unbind event

I have a bootstrap vue modal on a view page. When save is clicked, the save function emits an event. Works fine. When i close the modal and open it again then click on save, the save function is handled as expected emitting the function, however, it emits it twice (once for each time the modal was opened and closed. If i open and close the modal 5 times then click save, it calls the save function once but emits the function 5 times. I'm not sure how i can unbind the event when the modal closes using either typescript, vue, or bootstrap (any way other than jQuery :). Can anyone advise?
save() {
EventBus.$emit(MyEvents.RequestItemDetails);
}
// EventBus.ts
export const EventBus = new Vue();
export enum MyEvents{
RequestItemDetails = "request-item-details"
}
You've provided very little code for us to know what the problem actually is, but I'll take a guess.
If you're using a global event bus and you subscribe to an event on that bus from within a component, you need to make sure you unsubscribe from that event when the component is destroyed, otherwise your event handler function will be called multiple times because it gets registered multiple times on the bus.
For example:
import bus from './bus.js'
export default {
created() {
bus.$on('request-item-details', this.onRequestItemDetails)
},
destroyed() {
bus.$off('request-item-details', this.onRequestItemDetails)
},
methods: {
onRequestItemDetails() {
// Handle event
}
}
}
Your reply helped me find the solution. In my close method, all i needed to do was add "EventBus.$off('request-item-details')". That took care of it. Guilty of Overthinking again.
Thanks!

Is there a "onExpand" event or similar for dijit.TitlePane?

Is there any way to get an event callback when the dojo-dijit's TitlePane expands?
I can capture onClick on the TitlePane. However, that is not enough for me. I have a button for "Expand All" TitlePanes. When user clicks on that I iterate on all TitlePanes and call it's toggle() method. When that happens, onClick event is not fired (as expected). I was wondering if there is any event fired upon toggle().
Or any other smart ways to address it also will be appreciated.
After looking into documentation in detail, I do not think there is any built in event that is fired during the toggle/expand. I ended up firing a custom event, and that helped me get what I wanted.
This answer helped me - https://stackoverflow.com/a/12852043/3810374
Basically,
First using isOpen() method, ensure the title pane is not already expanded. Then call toggle() method, and fire a custom event like this:
require(["dojo/on"], function(on){
// Send event
on.emit(target, "onExpand", {
bubbles: true,
cancelable: true
});
});
And then handle the event:
require(["dojo/on"], function(on){
// register event handler
on(target, "onExpand", function(e){
// handle event
});
});
You may be wondering, why not just do the work right after toggle(), instead of going through the pain of firing/handling event. I needed to handle the event in a particular closure, where I have access to other objects and variables.

ReactTestUtils.Simulate can't trigger event bind by addEventListener?

Here is the example:
http://jsfiddle.net/hulufei/twr4thuh/7/
It just worked when bind onClick in virtual dom(like line 18), but If I comment line 18 and comment off line 8 to bind click with addEventListener, it failed.
So what's the problem?
TestUtils triggers events within react's synthetic event system, so the native event that addEventListener listens for is never going to be triggered. You will need to use the native click method on the element in your test:
var events = Events();
ReactTestUtils.renderIntoDocument(events);
events.refs.button.getDOMNode().click();
events.state.event.should.equal('click');
Additionally, you've misspelled clickHandler in your addEventListener definition.
jsfiddle
You can also simplify adding your event listener by reusing your prop definition:
componentDidMount: function () {
this.refs.button.getDOMNode().addEventListener('click', this.clickHandler);
},
Note:
Is there a reason why you want to use addEventListener instead of just passing an onClick attribute for your button? Unless there's a specific and good reason otherwise, i'd suggest doing things the react way when handling events for sanity :)
Edit
I originally mentioned that I did not know what TestUtils' SimulateNative.click did not trigger the event. I was wrong in thinking that it ever would since it would be simulating a native click event within the react even system. #thilo pointed me in the right direction :)
I had many problems while testing addEventListener, and I got the following conclusion.
You can create the events listener with pure javascript, jquery, but when running the tests with Jest I always had a problem.
The rendering of ReactTestUtils does not work directly with the document, and when we do:
For example, our events were added in the document, when rendering with ReactTestUtils it creates a div and renders it in the div, This way I could not get Simulate to trigger the call.
My first solution was to use jquery to create the listener and to test I did the render manually by appending the div in document.body, and triggered the events with the dispachEvent of javascript. But I thought the code was dirty, not the best way to work.
I made a sample code by adding the event and testing it with Jest, also have a test teaching to get all the listener that were created.
You can find the code here: https://github.com/LVCarnevalli/create-react-app/tree/master/src/components/datepicker
Component:
componentDidMount() {
ReactDOM.findDOMNode(this.datePicker.refs.input).addEventListener("change", (event) => {
const value = event.target.value;
this.handleChange(Moment(value).toISOString(), value);
});
}
Test:
it('change empty value date picker', () => {
const app = ReactTestUtils.renderIntoDocument(<Datepicker />);
const datePicker = ReactDOM.findDOMNode(app.datePicker.refs.input);
const value = "";
const event = new Event("change");
datePicker.value = value;
datePicker.dispatchEvent(event);
expect(app.state.formattedValue).toEqual(value);
});
Links:
window.addEventListener not triggered by simulated events: https://github.com/airbnb/enzyme/issues/426
Creating and triggering events: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events