I have a input made by vue.js's built-in components. I want to be able to set a value and submit this value to be able to create automated tests. How can I accomplish this?
Currently this is how I set value, but on submit this value is changed with the default data automatically.
Execute JavaScript return element.value = "${startDate}"
Simply run dispatchEvent method on the component itself. This will let Vue to set the value that you've entered to the form data
Execute JavaScript return element.dispatchEvent(new Event('input'));
Creating a new dispatchHandler fixed my problem!
Execute JavaScript return element.value = "${startDate}"
Execute JavaScript return element.dispatchEvent(new Event('input'));
Related
I created stand alone web component, with Vite and Vue3, to replace old jQuery libraries.
When rendered in html, it looks something like:
<custom-datepicker id="deliveryTime">
#shadow-root
<div>...actual component...</div>
</custom-datepicker>
When user select date it would be perfect if I can set attribute value to this element, like:
<custom-datepicker value="selected value HERE" ...
so the form can then use this value from the element by it's id.
Problem is that the only way I manage to achieve this is by emitting event (selected) from my web component and listening to that event, so the form can use value, like:
const datepicker = document.querySelector('#deliveryTime');
const dateSelected = (e) => {
datepicker.value = e.detail.val;
}
window.addEventListener('selected', dateSelected);
If I set value attribute within web component, rest of the app (Apache Velocity template) can't access it because it is in the shadow-root:
<custom-datepicker id="deliveryTime">
#shadow-root
<div value="selected value is sadly HERE">...actual component...</div>
</custom-datepicker>
Is it even possible to achieve this from inside the web component (so I can omit listener)?
I found solution, maybe not the cleanest one but it works :)
In my web-component, in mounted hook component is selected:
const dp = ref(null)
onMounted(() => {
dp.value = document.querySelector("#deliveryTime");
})
After date is selected, instead of emitting just set attribute:
dp.value.setAttribute('value', value)
What if you access the HTMLElement linked to your shadowhost and then use the "setAttribute" function on it ? Assuming you have access to the shadowRoot inside your component using 'this', I think something like that will do the trick (https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/host) :
const shadowHost = this.shadowRoot.host; // The HTMLElement linked to <custom-datepicker />
shadowHost.setAttribute("value", someValueOfYourChoice);
I am trying to change the input text (total INR) of the input field in this page by doing:
$(".cKOnhg").last().attr('value', Math.random() * 100000);
When inspected the "value" attribute of the input changes to a random number, however it automatically changes back to 0 (or the number that was manually inputted) after few seconds.
I have tried trigger() and the sendkeys plugin mentioned here: https://stackoverflow.com/a/13946504/82985
Nothing seems to work. Is it even possible on this page to change the input value exactly like how a human would do?
I'm trying to change the input values and auto-submit the form.
This page is using React under the hood. The problem when you try to programmatically set the value is that you only update the DOM, but the underlying React's state remains the same, so the DOM gets reset on the next render tick.
In order to correctly update the input value, use this code (you don't need jQuery at all):
function setNativeValue(element, value) {
const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
const prototype = Object.getPrototypeOf(element);
const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
if (valueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, value);
} else {
valueSetter.call(element, value);
}
}
// Wait for the DOM to be fully rendered by React before doing anything
window.addEventListener("load", function() {
const el = Array.from(document.querySelectorAll('.cKOnhg')).pop();
setNativeValue(el, Math.random() * 100000);
el.dispatchEvent(new Event('input', { bubbles: true }));
});
Explanation: in order to trigger a value change in React, you have to bypass the custom value setter that is added by the framework on the HTMLInputElement instance, which overrides the one from HTMLInputElement.prototype (the native one). Once you've done that, emit an input event to notify the framework that the value has changed, for correct taking into account by the framework.
More information about this: https://github.com/facebook/react/issues/10135
In form.io form builder i am adding custom validation but the default is to trigger the validation on change i want to set it to on blur.
I have tried the following code on the custom validation tab:
let field = document.querySelector('input[name="data[nametest]"]');
field.addEventListener("blur", checkValidation);
function checkValidation() {
console.log('checking...');
valid = (input.length > 5) ? true : 'Test name must be at least 5 characters long' ;
}
the code is running on blur but it is not showing the error the valid global variable is set to the correct error message its just not showing on the form also i notice that the more characters on the textfield the more the event gets trigger on blur, I would be gratefull for any help.
Thanks!
When you are in the Form Builder view, validity checks are disabled. You may test simple validations in the component settings modal:
Now, in case you want to trigger an action on blur, you must consider that custom validation is not persistent and is calculated on every evaluation, meaning that whatever you do with it after it has been evaluated will not affect the component itself. You will need to attach the event directly into the component instance.
You can achieve this in two ways:
Using a Hidden Component
Create a hidden component in your form and set it to not persistent (you don't want to store a value, just run) and define a custom default script to run at form rendered.
const { root } = instance;
const comp = root ? root.getComponent('key') : null;
if (comp) {
// remove any listener to avoid duplicates
comp.off('blur');
// define the on blur listener
comp.on('blur', () => {
console.log('blur');
});
}
On Form Ready
Formio.createForm(document.getElementById('formio'), form).then((formio) => {
const component = formio.getComponent('key');
if (component) {
component.on('focus', () => {
console.log('focus');
});
component.on('blur', () => {
console.log('blur');
});
}
});
Here is a working example: https://jsfiddle.net/airarrazaval/ongcuwt2/
I don't know since which version this option exists, but at least with version 4.13 the form builder has a specific property to address your concern - Validate On:
This should work perfectly fine with your custom validation code, as well.
I need to add some query paramaters to my url as a person checks off checkboxes.
I am using react router so I do something like this in my checkboxes on change event.
const stringified = queryString.stringify(parsed);
const path = `${this.props.location.pathname}?${stringified}`;
this.props.history.replace(path)
This does however seem to cause a re-render of the page(not sure if this should be happening, would prefer it not to do that so maybe I got to use something other than replace?).
I wanted to check on componentDidMount the url to see if the value is there. If it is there then I wanted to update the state of the checkbox.
#observable
isChecked = false;
#action
componentDidMount() {
const parsed = queryString.parse(this.props.location.search);
this.isChecked = parsed && parsed["param"] === this.props.option;
}
However I don't see the onChange being trigger.
Right now I have on change a function that takes the value and uses it to filter, so I need the function to run.
I could put that function in the componentDidMount but I wanted to make sure before I do that, there is nothing I am missing on why the change event is not be fired.
Try setting the state in the constructor() and incomponentDidUpdate().
When a URL parameter is added to the same route, the existing component is utilized (i.e. an update event) vs. a new one being created. As a result, you won't see a componentDidMount() event.
Another option/solution is to update the state of isChecked directly and push the history/url change.
If what you are trying to prevent is the page refresh use this built in function in your onSubmit event(if I understand your question correctly.)
event.preventDefault();
It stops the browser from auto-refreshing! Make sure to call event in your function though.
ie
onSubmit=(event)=>{
event.preventDefault();
//rest of code
}
If you are trying to filter, the es6 .filter method is useful for checkboxes. I personally used a select dropdown menu to filter the options and selectively show the ticked items in a ToDo List: "Done" "Active" "Completed" and used those states in my filter method.
I have a simple textarea where I want the user to be able to select/highlight text to make it bold, italicized, etc., much like the one I'm writing in now.
I actually get it working using a onKeyDown method and then using window.getSelection(), but I feel it's the wrong approach to use window in React. Correct? If so, what do I use instead?
handleKeyDown(event) {
const highlightedText = window.getSelection().toString()
console.log(highlightedText)
},
render() {
return (
<textarea onKeyDown={this.handleKeyDown} />
)
}
The time when things can go wrong is when you modify the DOM outside of React. But this is not the case.
I don't mind calling window.getSelection in my react code. I've been using document methods/attrs like document.activeElement and window methods/attr like window.innerHeight and setTimeout. I have come across no problem and I did not find any other better way to get what I want.
This does need some attention in test though. You need to set up the window object and make it available to your test code.
It's ok to use window.getSelection in React. The only issue I see here in terms of breaking the component model and getting unexpected results, is the case where you call the method inside your component, but the selection is actually on a different element on the page.
In your case since you are calling getSelection inside the onKeyDown handler, you know the selection must have come from this component instance, since it needs to be focused to receive the event.
But if you would like to be able to get the selection at any time inside a component in a safe way, you could create a member function on the component to check if it's focused using refs:
getSelection() {
return (this.refs.container === document.activeElement) ?
window.getSelection() : null;
}
render() {
return (
<textarea onKeyDown={this.handleKeyDown} ref="container" />
)
}
Here getSelection() will return the selection if it's within this component instance, otherwise null.