I'm using ant design. I have a form. In that form I have submit button and select dropdown.
when I click submit button it triggers the form submit action.
I need to submit form and get values on select change event.
Code sandbox: https://codesandbox.io/s/xrpzw7wn8q
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log("Received values of form: ", values);
}
});
};
I will try to answer this question in a more general way because it pops in the search results and it may help some people.
To submit a select form on a change event (without a submit button) in React, you have to do two things:
use the "onChange" property to fire a function to send the value.
in this function, you have to trigger the submit action of the form.
To do number 2, in classical javascript you would grab a reference to the form and then use the submit() method. In React, to grab the form, you can use "useRef". The submit() method is then accessible on the "current" property. Here is an implementation:
import { useRef }, React from "react"
export default function SelectOnChange () {
const selectForm = useRef(null)
const handleSubmit = () => {selectForm.current.submit()}
return (
<form ref={selectForm} method="get" onChange={handleSubmit}>
<select name="sort" id="sort">
<option value="relevance">Relevance</option>
<option value="score">Score</option>
</select>
</form>
)
}
You can add a callback to the onchange event of the Ant Design Select component, that could handle the form submit:
<Select
allowClear
onChange={
(value) => {
// your code to submit the form
}
}
>
<Option key={1} value={1}>
something 1
</Option>
<Option key={2} value={2}>
something 2
</Option>
</Select>
BUT from an UX perspective, if the submit button has to be present, it should be it to trigger submitting
You can do something along those lines:
<Select allowClear onSelect={ (val, event) => this.handleSubmit(event) }>
Add the onChange() or onSelect() from ant design select and access the values from the form in the callbacks.
state={
selectValue : "default value",
otherFormItemValue: "default other value"
}
handleSubmit = () => {
serviceCallToSubmitForm(this.state.selectValue, this.state.otherFormItemValue);
}
//In the render() of component
<Select
onChange={
//or onSelect
(value) => {
this.setState({selectValue: value});
this.handleSubmit()
}
}
>
<Option key={1} value={"value 1"}>
something 1
</Option>
<Option key={2} value={"value 2"}>
something 2
</Option>
</Select>
<Button onClick={this.handleSubmit}>Submit</Button>
Hope this helps and is clear enough.
The handleSubmit function is used to access the form values from the state and submit it.
The onChange function call it used to :
1. Store the dropdown value in the state
2. call the handleSubmit function to actually submit in the same action [not recommended UX-wise]
Here is code sandbox.
https://codesandbox.io/s/r00v7x8r7q
Select dropdown item and check console for the respected value.
Getfield decorator doesn't have onchange option, so remove it and add onchange event to select tag instead of getfield decorator.
Check ant docs for available options.
https://ant.design/components/form/
getFieldDecorator(id, options) parameters
Related
When I try to reset a field with cy.clear() and the element is a dropdown,
it is failed because it requires a valid clearable element.
When('#userSettings.actions I reset Gender', () => { userSettings.form.getGenderDropdown().clear(); });
Cypress gives the error as, /
cy.clear() failed because it requires a valid clearable element.
Please see How do I clear a multi-select input using Cypress.
There is usually an input underlying a dropdown, so possible suggestions you might use -
userSettings.form.getGenderDropdown()
.invoke('val', '')
.trigger('change')
userSettings.form.getGenderDropdown()
.find('input')
.invoke('val', '')
.trigger('change')
Some other suggestions floating around, but a little bit dubious -
userSettings.form.getGenderDropdown()
.type({selectall}{backspace})
userSettings.form.getGenderDropdown()
.select([])
I notice in the Cypress test clear_spec.js
context('works on input type', () => {
const inputTypes = [
'date',
'datetime',
'datetime-local',
'email',
'month',
'number',
'password',
'search',
'tel',
'text',
'time',
'url',
'week',
]
inputTypes.forEach((type) => {
it(type, () => {
cy.get(`#${type}-with-value`).clear().then(($input) => {
expect($input.val()).to.equal('')
})
})
})
})
which is a pretty long list of valid types, so if you do have an input behind the form control this might be all you need
userSettings.form.getGenderDropdown()
.find('input')
.clear()
This snippet does the job. Please learn it and try to modify it for you. I selected one of the available options, then deleted 'disabled' atrribute from the default option to select it in future.
it('example', function () {
cy.visit('https://www.seleniumeasy.com/test/basic-select-dropdown-demo.html');
cy.get('[id="select-demo"]').select('Monday')
cy.get('[id="select-demo"]').find('option').eq(0).then(($elem) => {
$elem.removeAttr('disabled')
})
cy.get('[id="select-demo"]').select('Please select')
})
One way is to reset the form, presuming clearing the whole form is what you are aiming for.
Please see HTMLFormElement.reset()
The HTMLFormElement.reset() method restores a form element's default values. This method does the same thing as clicking the form's reset button.
If a form control (such as a reset button) has a name or id of reset it will mask the form's reset method. It does not reset other attributes in the input, such as disabled.
HTML
<form>
<select class="form-control" id="select-demo">
<option value="" selected="" disabled="">Please select gender</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Unknown">Unknown</option>
</select>
</form>
Test
it('resets the form values', () => {
cy.get('select').should('have.value', null); // starts with empty value
cy.get('select').select('Female') // select an option
.should('have.value', 'Female');
cy.get('form').then($element => $element[0].reset())
cy.get('select').should('have.value', null); // now empty again
})
Let's say I have a function which returns a dropdown. This function gets called from some parent, where the parent passes in props including a state key, array, and onChange. The dropdown is created dynamically from the items in the array. What I want to happen is, when an option in the dropdown is selected, the parents passed in state key gets updated to the value of whatever was selected. Currently, I am trying to do this by setting an onClick handler per , which doesn't work. Instead, I am met with either no or undefined values (described more below).
Example flow:
Parent passes in aStateKey (actual state key), an array to be used as dropdown values, and an onChange function to be used to update aStateKey
The dropdown menu is created from the passed inarray
A dropdown item is selected
aStateKey (which was passed in as a prop) gets updated via the passed in onChange function.
I understand that the traditional method is to give and onChange handler, but I am having troubles working out how to get the desired described above.
Parent
state = { aStateKey: "" };
someArray = ["test", "another test"];
updateField = (name, value) => {
console.log("Updating field: " + name + " with value: " + value);
}
return(
<div>
<CreateDropdown name="aStateKey" items={this.someArray} onChange={this.updateField} />
</div>
);
CreateDropdown
function CreateDropdown(props) {
const handleClick = event => {
console.log("changed name:" + event.name + "changed value: " + event.value);
props.onChange(event.name, event.value);
};
return (
<div>
<select>
{props.items.map(field => (
<option key={field} value={field} name={props.name} onClick={handleClick}>
{field}
</option>
))}
</select>
</div>
);
}
Console log
Shows nothing! However, if I move the onClick from <option> to <select>, i.e.
return (
<div>
<select onChange={handleClick}>
{props.items.map(field => (
<option key={field} value={field} name={props.name}>
{field}
</option>
))}
</select>
</div>
);
The console shows:
Updating field: undefined with value: undefined.
changed name:undefinedchanged value: undefined
How can I achieve my desired behavior?
your target form this event is select and use onChange and here the updated function you need:
function CreateDropdown(props) {
return (
<div>
<select name={props.name} onChange={e =>
props.onChange(e.target.name, e.target.value);}>
{props.items.map(field => (
<option key={field} value={field}
{field}
</option>
))}
</select>
</div>
);
}
UPDATE #1
Inside handleClick, you are using event.name and event.value to get the target values you want.
instead use event.target.name and event.target.value
Try using onChange instead of onClick in your select element.
It belongs to select not option elements.
I am utilizing VueJS and it's components to build a large series of datalists and selectors.. all with a submit button at the end of it when the form is validated...
so far I can make a datalist inside a component that renders options and has type completion.. works great! BUT when I attempted to turn the thing into a VueJS Component, and pass in the dataarray as a property... my list of options no longer render
Two Datalist elements...
Top one is the "raw" datalist, which works 100%
But when I goto the vue.js component version, nothing shown as an option...
it's just not there, when I mouse over like the first one...
The datalist VueJS Component
<template>
<div>
<input type="text" v-model="item" list="data_input" v-on:input="selectionChanged">
<datalist id="yourdatalist">
<option v-for="item in data_input">{{item}}</option>
</datalist>
</div>
</template>
<script>
export default {
name: 'Datalist',
props: ['inputDataList'],
data () {
return {
selection: '',
item:'',
data_input:this.inputDataList
}
},
methods: {
selectionChanged: function(element) {
console.log("selection = "+this.selection+", new value = " + element.target.value);
var newSelection = element.target.value;
if (newSelection != this.selection) {
// newSelection changes on every keystroke, so you must keep diffing it with your known data
for (var i=0; i<this.data_input.length; i++) {
if (this.data_input[i] == newSelection) {
this.selection = newSelection
console.log("selection = "+this.selection+" now");
this.$emit('selectionChanged', this.selection);
}
}
}
},
},
}
</script>
The calling component HTML code
<p>Examples of Datalists</p>
<input type="text" v-model="film" list="films" v-on:input="filmChanged">
<datalist id="films">
<option v-for="film in films">{{film}}</option>
</datalist>
<div v-if="focusedfilm">
<h6>You have picked {{focusedfilm}}</h6>
</div>
<br/>
<p>Examples of Child Component Datalist</p>
<Datalist :inputDataList="films"/>
Set the attribute 'list' equal to the attribute 'id' of the datalist.
Change
<datalist id="yourdatalist"> to <datalist id="data_input">
Regards
If Alfredo Lanzetta post his answer, you should accept his because he came with it first. I just want to explain why the solution works.
If you have the following code where you want a dropdrown list for an input field
<input type="text" v-model="item" list="data_input" v-on:input="selectionChanged">
<datalist id="yourdatalist">
<option v-for="item in data_input">{{item}}</option>
</datalist>
To correctly assign the datalist to the input field, the input field needs to have a link to said datalast. You can do that with the list property of the input field.
The way to link the two, is to set the list property of the input field to the id of the datalist. As you can see in example from your code, the datalist has the id yourdatalist but the input field has de list property set to data_input, thus it is looking for a datalist with the id data_input. Since there is no datalist with said id, you don't get to see that dropdrown list.
I have a drop down in my form (https://ant.design/components/select). In this select drop down I have the onChange to call a function. Inside 'onChange' I want to pass the event as a parameter to my function. The problem is: when the onChange occurs, only the selected value is passed, but I want the entire event.
Here is the code:
export default class MyForm extends Component {
constructor() {
super();
this.handleOnChange = this.handleOnChange.bind(this);
}
handleOnChange = (event) => {
console.log(event); // here I'm receiving only the value selected (1 or 2)
}
render() {
render(
<Form>
<Select onChange={this.handleOnChange}>
<Option value="1">text 1</Option>
<Option value="2">text 2</Option>
</Select>
</Form>
)
}
}
In the console.log() I'm receiving only the selected value. Is there a way to pass the entire event object to the function handleOnChange()?
I found a solution. Just use: onSelect(), passing the value and the event.
handleOnChange = (value, event) => {
...code here
}
render() {
render(
<Form>
<Select onSelect={(value, event) => this.handleOnChange(value, event)}>
<Option value="1">text 1</Option>
<Option value="2">text 2</Option>
</Select>
</Form>
)
}
The Select component that you use is the one that handle the onChange and call your "outer" function.
What you can try is use the synthetic event variable inside your function, it might work:
handleOnChange = (selectedValue) => {
console.log(selectedValue); // The value from the inner component
console.log(event); // usually you have access to this variable
}
Try this, if you dont want to bind in callback in Select onSelect/onChange:
toggleActive = name => event => {
console.log("name: ",name) // prints "name: Active!"
console.log("event: ",event) // event is some data
}
<Select
mode="multiple"
style={{ width: '91%' }}
placeholder="Stuff"
value={this.props.value}
onChange={this.toggleActive("Active!")}
>
I have many forms on my site. When the Submit is triggered on the form I expect to receive an id of the form and the option selected.
html
<form name="order">
<select id="count">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select><br/>
<input type="text" name="id" value="6" />
<input href="#" type="submit" value="Submit" />
</form>
JavaScript
var fancyboxOptions = {
ajax : {
type: "POST",
data: {
id: null,
count: null
}
}
}
$(document).ready(function() {
fancyboxOptions.ajax.data.id = $('input[name="id"]').val();
fancyboxOptions.ajax.data.count = $('#count').val();
$('div#buy input').fancybox(fancyboxOptions);
$('#count').change(function() {
fancyboxOptions.ajax.data.count = $('#count').val();
});
With this code I receive only data from the first form -- when the submit is triggered other forms I receive data from the first form rather than from the form I pressed submit on.
How do I restructure my code, so the form submits triggers the submit to give me only the the data in the form for which I pressed submit.
PS Do not pay attention a fancybox, it's work good.
May want to change your code to something like this
<script>
$('input[name=id]').parent().change(function(){
fancyboxOptions.ajax.data.id = $(this).find('input[name="id"]').val();
fancyboxOptions.ajax.data.count = $(this).find('#count').val();
});
</script>
This will install a change handler on each form which contain a input field named id, and the callback function (which is installed on the parent() form ) will have access to "this" which the can navigate the DOM and find all the sub-fields relative to the form node.
Do you need to loop through all the forms on your page and get their values after clicking one button? If so, try this:
$('form').each(function(){
var currentForm = $(this);
var someValue = currentForm.find('input[name="id"]').val();
// do the rest here
});
If that's not your question, then maybe it has something to do with using ids for your inputs instead of classes. You can only use an id once, so if your other forms also include < select id="count"> then when jQuery reads that value, it will only ever return the value of the first one.
Hope this helps...