Dynamically added rows onchange event javascript - javascript

Im using javascript and jsp for creating rows dynamically. When value in a particular cell changes, onchange event will be fired and the message will be given.
When an onchange event is used in java script, first i tried to pass the id directly,
element1.onchange=checkInputValue(element1.id);
onchange event fired even when cell gets created. Later when i changed to
element1.onchange = function(evt){ testInputElement(this.id); };
and inside "testInputElement", the onchange event is called and the function worked fine. What is the use of this? Why we need to pass the function inside the function?
Is there any other way?
TIA

The onchange property allows you to specify a function that should be executed whenever that element changes. In your first example you are assigning the return value of checkInputValue to onchange, which the element can't execute.
What you want to do is assign a function that should be executed whenver the elemnent changes, which you correctly do in the second example.
If you don't want to pass a new function to onchange, you could instead modify checkInputValue to accept a change event. The change event contains information about where the event originated, including the elemnt.
function handleOnChange(event) {
var id = event.target.id;
// do some stuff
}
// pass a reference to the function, rather than executing it.
// when element1 changes it will call handleOnChange, and pass an
// event object
element1.onchange = handleOnChange;

Related

In jest/enzyme, how do you simulate a click on an element with eventListener bound by [element].addEventListener (not window.addEventListener)?

In react, when you have an element with an onClick prop, it's easy to use Enzyme's .simulate("click") method to click it. However, there's an example in my codebase where an element is referenced by React's "ref" prop, and then that element's .addEventListener is invoked to bind an event handler to it.
I've provided a code example:https://codesandbox.io/s/1z4xok048j
The key line is this:
if (this.refs.hey) {
this.refs.hey.addEventListener("click", this.handleClick);
}
In the code example, the eventHandler is not bound until componentDidUpdate is run, so if you click on the "click me to increment counter" div, the child element receives new props and its componentDidUpdate triggers. Then if you click on the Child element, its eventHandler triggers as expected. However, I can't reproduce this behavior in my Enzyme/Jest tests.
I've done the obvious .simulate("click") method from Enzyme and it does not work; when I change from using refs and the event listeners to using an onClick, .simulate("click") works as expected. However, removing the refs causes other bugs to surface and I haven't been able to figure out why, so I'd prefer to find out a way to simulate clicking the button.
The code for .simulate("click") actually looks for the onClick function and passes the params to it, there is no 'actual' click going on. You might have to mock the addEventListener functions with something like
// Set-up event listener mock
const map = {};
window.addEventListener = jest.genMockFn().mockImpl((event, callback) => {
map[event] = callback;
});
The answer is actually really simple. The general idea is to .find the node and get the underlying HTML DOM Node with .getDOMNode(). Once you have it, replace its .addEventListener like so:
const map ={};
const namedByRefComponent = component.find(".some-class-name");
const namedByRefDomNode = namedByRefComponent.getDOMNode();
namedByRefDomNode.addEventListener = jest.fn().mockImplementation((event, cb) => {
map[event] = cb;
});
after that, your DOM node's event handlers can be found in map and you can invoke them in the tests.

Vue // this.$root.$off unsubscribes all instances of the component from the global event

I have a custom input validation component that I use in a form. Something like 15 instances of this component around the app. It has a beforeDestroy method in which I unsubscribe from global event called triggerGlobalValidation which triggers validation before I send request to server. As expected it's triggered only once inside this certain component.
There is a container with v-if parameter which contains one instance of the component. So when v-if="false" I expect this certain component to unsubscribe from event and get destroyed. It goes well accept for one thing: somehow this component unsubscribes ALL other instances of it from the triggerGlobalValidation event as well.
I've tested the behavior with v-show and it works as expected - all other instances keep subscribed, but since the v-show field is required for the form it's blocking validation even without being shown in the DOM. I also tested above mentioned components behavior by removing the this.$root.$off("triggerGlobalValidation") and it also works as expected + polluting the global root.
Vue documentation on $off method is saying:
If no arguments are provided, remove all event listeners;
If only the event is provided, remove all listeners for that event;
If both event and callback are given, remove the listener for that
specific callback only.
Is it possible to somehow mention in the callback, that this $off method shouldn't unsubscribe all of its instances from the event, but just this certain one being destroyed?
Check it out in codesandbox
As answered in the issue, you need to save the handler and pass it again to $off
mounted() {
this.fn = () => {
this.toggleWarning();
}
this.$root.$on("triggerChildComponents", this.fn);
},
beforeDestroy() {
this.$root.$off("triggerChildComponents", this.fn);
},

simulating an onClick method with a parameter using Enzyme in React

I'm trying to simulate an onClick method in my unit tests using Enzyme for React. I've found many guides to simulating an onClick that takes some event e, such as:
handleClick(e) {
// Does something
}
....
<MyComponent
onClick = {handleClick}
></MyComponent>
However I want to be able to simulate my onClick which does not take the event as a parameter but takes something else instead, ie:
onClick = {() => handleClick(myParam)}
I've tried using .simulate('click', [myParam]); but it did not pass the parameter as I expected.
How would I go about simulating a click that sends a specific parameter to the handler?
according to the documentaton it states that:
.simulate(event[, mock]) => Self Simulate events
Arguments
event (String): The event name to be simulated mock (Object
[optional]): A mock event object that will be merged with the
event object passed to the handlers.
so you need to fix your code and pass an object:
.simulate('click', {myParam});
You can also take a look at the implementaion and see how it is passed to the event handler here:
simulate(event, ...args) {
const handler = this.prop(propFromEvent(event));
if (handler) {
withSetStateAllowed(() => {
// TODO(lmr): create/use synthetic events
// TODO(lmr): emulate React's event propagation
performBatchedUpdates(this, () => {
handler(...args);
});
this.root.update();
});
}
return this;
}

Dispatch an "oninput" event with a custom { target : { value } } data

I'm trying to use dispatchEvent on an <input> element in a unit test to trigger its "oninput" handler with a custom {target: {value: "data"}}
This guide only tells you how to trigger a CustomEvent. But I don't think that'll work as it only lets you specify a "details" property. I'm actually trying to trigger it with something like {target: {value: "data"}}
There's also InputEvent but it too seems to take the same "details" property only.
Here's my <input>:
<input
oninput={handleOnInput} // jsx
>
...
function handleOnInput(e){
const data = e.target.value; // << needs to be mocked
}
And this is my test code:
getThatInputEl().dispatchEvent(what can trigger "input" with {target: {value: "data"}} ?)
Is there a way you can dispatch an "input" event with a custom {target: value: "data"}?
When you dispatch input event on actual input element e.target is always set to the element, you can't override it - you can only pass object with additional data. To solve your problem you just have to set value of input before dispatching event or you can test event handler itself

Register Firebase Listener Without Calling It?

Is it possible to register a Firebase listener function without calling it when you register it?
For example:
this.gamestateURL.on('value', function(snapshot){
self.GameStateChangeEvent(snapshot);
});
GameStateChangeEvent function fires immediately upon setting up the listener.
Thank you.
Unfortunately, no. The docs specifically state:
This event will trigger once with the initial data stored at this location, and then trigger again each time the data changes. The DataSnapshot passed to the callback will be for the location at which on() was called. It won't trigger until the entire contents has been synchronized. If the location has no data, it will be triggered with an empty DataSnapshot (val() will return null).
You could, however do something like this:
var ref = this.gamestateURL // or however you create a ref
function doSomethingWithAddedOrChangedSnapshot(snapshot) {
// this function is called whenever a child is added
// or changed
}
// assuming you have "timestamp" property on these objects
// it will not be called back with any snapshots on initialization
// because the timestamp of existing snapshots will not be greater
// than the current time
ref.orderByChild('timestamp')
.startAt(new Date().getTime())
.on('child_added', doSomethingWithAddedOrChangedSnapshot);
ref.on('child_changed', doSomethingWithAddedOrChangedSnapshot);
ref.once('value', function(snapshot){
// get the initial state once
// this snapshot represents all the items on this ref
// this will only fire once on initialization
initializeGameData(snapshot.val());
});
In English:
Create one function that handles the updated/added child
start listening to the child_added event for all children added after the current timestamp (unix time since epoch). This also assumes you're storing the timestamp on these children.
start listening to the child_changed event for any child that is changed.
grab all the values of the ref once to initialize your data.
not sure if your use case needs to handle 'child_removed' or 'child_moved'

Categories