setState to the current item selected from dropdown - javascript

var Dummy= React.createClass({
onSelect: function(e) {
this.setstate({ selectedItem: e.currentTarget.value })
},
render: function() {
return <select onChange={this.onSelect.bind(this)}>
<option value="1">Item 1</option>
<option value="2">Item 2</option>
<option value="3">Item 3</option>
</select>
}
});
In the code above I'm trying to set state to the current item selected from the dropdown. I know an easy way of doing it is e.currentTarget.value but it returns the value of the clicked item. I want the inner text (ie, Item 1, 2 etc.)
How can I achieve this?

Just use the text:
this.setstate({ selectedItem: e.target.options[e.target.selectedIndex].text })

Related

Auto-select first <select> option when loading async options in Vue 3

I have a <select> HTML element which I want to v-model bind to a ref value in Vue.js 3's setup() method. So when a user selects a different option, the Form.ProductID ref updates.
Here is the <select> code:
<select v-model="Form.ProductID" id="ProductID" name="ProductID">
<option value="1">Option A</option>
<option value="2">Option B</option>
<option value="3">Option C</option>
</select>
And setup():
export default {
name: "ComponentProductSelector",
setup() {
const Form = ref({
ProductID: '2',
Price: null,
Currency: null
})
onMounted(() => Form.value.ProductID)
document.querySelector("#ProductID option:first-of-type")
}
}
On first load in vue devtools, it shows the data as being:
Form (Object Ref)
ProductID: "[object HTMLOptionElement]"
When I select an option in the <select> element, Form.ProductID updates as expected and shows which option I selected e.g.:
Form (Object Ref)
ProductID: 3
The problem is that on the page first load, the <select> element is not selecting the option with value="2" even though I am hard coding it in the setup(). It just shows a blank option! However if I change the <select> element to the following code then it does:
<select ref="Form.ProductID" id="ProductID" name="ProductID">
<option value="1">Option A</option>
<option value="2">Option B</option>
<option value="3">Option C</option>
</select>
Now the option with value="2" is selected by default when the component is rendered, however the actual value of Form.ProductID does not update and vue devtools continues to show ProductID: "[object HTMLOptionElement]" as the data.
How can I get the <select> element to work using v-model and also select a default option when the component loads?
Answering the updated question in comments about how to select the first option when async loading. Once the data is loaded, set the value of Form to the first item in the options array (cloned to avoid mutating it), rather than manually manipulating the input DOM.
For example:
<select v-model="Form.ProductID" id="ProductID" name="ProductID" v-if="options">
<option v-for="option in options" :key="option.ProductID" :value="option.ProductID">
{{ option.ProductID }}
</option>
</select>
setup() {
const options = ref(null);
const Form = ref(null);
axios.get('...').then(response => {
options.value = response.data;
Form.value = { ...options.value[0] }; // Clone and select first option
});
return { options, Form }
}
There's a v-if on the <select> to delay its rendering until the data is ready.
Here's a demo:
const { createApp, ref } = Vue;
const app = createApp({
setup() {
const options = ref(null);
const Form = ref(null);
axios.get('https://jsonplaceholder.typicode.com/posts').then(response => {
options.value = response.data;
Form.value = { ...options.value[0] }; // Clone and select first option
});
return { options, Form }
}
});
app.mount("#app");
<div id="app">
<select v-model="Form.id" id="ProductID" name="ProductID" v-if="options">
<option v-for="option in options" :key="option.id" :value="option.id">
{{ option.id }}
</option>
</select>
</div>
<script src="https://unpkg.com/vue#next"></script>
<script src="https://unpkg.com/axios"></script>

Multiple <options> inside of logical && operator

I'm trying to create a dependent select box that has different listed depending on a parent select. I'm assuming that the code is failing because the options need to be wrapped inside of a container, but I'm not sure what container they can be wrapped in if I do not want to recreate the for each state.
To be honest, I'm not even sure this is the best way to go about it. I'm still very new to React and JS in general. This company has locations in more than two states as well, so perhaps there is a better way to scale this? Thank you
My code so far:
<select
className="select"
name="selectCity"
onChange={this.onCityChange}
>
<option value="" defaultValue>Select a City</option>
{
this.state.state === 'california' &&
<option value="los-angeles">Los Angeles</option>
<option value="san-diego">San Diego</option>
}
{
this.state.state === 'texas' &&
<option value="austin">austin</option>
<option value="dallas">Dallas</option>
}
</select>
You're right, even if you could have multiple elements without a parent element, that's still less than optimal for many reasons.
It's better to have a proper data structure and loop through the data set. For example:
const cities = {
california: [
{ value: "los-angeles", name: "Los Angeles" },
{ value: "san-diego", name: "San Diego" }
],
texas: [
{ value: "austin", name: "Austin" },
{ value: "dallas", name: "Dallas" }
]
// and so on
};
<select
className="select"
name="selectCity"
onChange={this.onCityChange}
>
<option value="" defaultValue>Select a City</option>
{cities[this.state.state].map( city => <option value={city.value}>{city.name}</option> )}
</select>
You can use React.Fragment to group elements together when you don't want a wrapping element in the DOM.
<select className="select" name="selectCity" onChange={this.onCityChange}>
<option value="" defaultValue>
Select a City
</option>
{this.state.state === "california" && (
<React.Fragment>
<option value="los-angeles">Los Angeles</option>
<option value="san-diego">San Diego</option>
</React.Fragment>
)}
{this.state.state === "texas" && (
<React.Fragment>
<option value="austin">austin</option>
<option value="dallas">Dallas</option>
</React.Fragment>
)}
</select>
There are a few approaches you could take here. Separation of concerns makes your code more readable and maintainable later. Not seeing the rest of your code, I'm not sure exactly how I would plug into your component. What do you think of something like
const cities = {
'california': {
'los-angeles': 'Los Angeles',
'san-diego': 'San Diego',
},
'texas': {
'austin': 'Austin',
'dallas': 'Dallas',
},
};
const getOptions = (state) => {
const cities = Object.keys(cities[state]);
return cities.map(city => <option value={city}>{cities[city]}</option>);
}
<select
className="select"
name="selectCity"
onChange={this.onCityChange}
>
<option value="" defaultValue>Select a City</option>
{
getOptions(this.state.state);
}
</select>

issue with select list not highlighting correct value in react

I have the following class:
class SelectCategory extends Component {
constructor(props){
super(props);
this.state = {value: props.book.category};
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
console.log('set state handle change', event.target.value)
this.props.onChange(this.props.book, event.target.value)
}
render() {
return (
<select value={this.state.value} onChange={this.handleChange} >
<option value="none" disabled>Move to...</option>
<option value="currentlyReading">Currently Reading</option>
<option value="wantToRead">Want to Read</option>
<option value="read">Read</option>
<option value="none">None</option>
</select>)
}
}
The issue i have is that the state changes when i select a different value, but the selected item remains the same.
my question is if the state is being set to the one that i want, why isnt it being reflected in the actual select element?
Thanks for the help!

How to get the text of the selected option using vuejs?

I want to get the text of a selected option input and display it somewhere else. I know how to do it using jQuery but I want to know how can we do it using Vuejs.
Here is how we do in jQuery. I mean the text of Selected Option not the value.
var mytext = $("#customerName option:selected").text();
Here is my HTML
<select name="customerName" id="">
<option value="1">Jan</option>
<option value="2">Doe</option>
<option value="3">Khan</option>
</select>
{{customerName}}
Now how can I display the selected option under it. like Jan, Doe, Khan ?
Instead of define the value only as the id, you can bind the selected value with an object with two attributes: value and text.
For example with products:
<div id="app">
<select v-model="selected">
<option v-for="product in products" v-bind:value="{ id: product.id, text: product.name }">
{{ product.name }}
</option>
</select>
</div>
Then you can access to the text through the "value":
<h1>Value:
{{selected.id}}
</h1>
<h1>Text:
{{selected.text}}
</h1>
Working example
var app = new Vue({
el: '#app',
data: {
selected: '',
products: [
{id: 1, name: 'A'},
{id: 2, name: 'B'},
{id: 3, name: 'C'}
]
}
})
<div id="app">
<select v-model="selected">
<option v-for="product in products" v-bind:value="{ id: product.id, text: product.name }">{{ product.name }}
</option>
</select>
<h1>Value:
{{selected.id}}
</h1>
<h1>Text:
{{selected.text}}
</h1>
</div>
<script src="https://unpkg.com/vue#2.4.4/dist/vue.js"></script>
I had this issue, where I needed to get a data attribute from a selected option, this is how I handled it:
<select #change="handleChange">
<option value="1" data-foo="bar123">Bar</option>
<option value="2" data-foo="baz456">Baz</option>
<option value="3" data-foo="fiz789">Fiz</option>
</select>
and in the Vue methods:
methods: {
handleChange(e) {
if(e.target.options.selectedIndex > -1) {
console.log(e.target.options[e.target.options.selectedIndex].dataset.foo)
}
}
}
But you can change it to get innerText or whatever. If you're using jQuery you can $(e).find(':selected').data('foo') or $(e).find(':selected').text() to be a bit shorter.
If you are binding a model to the select element, it will only return the value (if set) or the contents of the option if there is no value set (like it would on submitting a form).
** EDIT **
I would say that the answer #MrMojoRisin gave is a much more elegant way of solving this.
The below code worked to get the Text from the selected option. I added a v-on:change , which calls a function onChange() to the select element.
methods:{
onChange: function(e){
var id = e.target.value;
var name = e.target.options[e.target.options.selectedIndex].text;
console.log('id ',id );
console.log('name ',name );
},
<select name="customerName" id="" v-on:change="onChangeSite($event)">
<option value="1">Jan</option>
<option value="2">Doe</option>
<option value="3">Khan</option>
</select>
Assuming you have a customers list and a selected customer on your model, an example like below should work perfect:
<select v-model="theCustomer">
<option :value="customer" v-for="customer in customers">{{customer.name}}</option>
</select>
<h1>{{theCustomer.title}} {{theCustomer.name}}</h1>
I guess your values should be in the JS. Then you can easily manipulate it. Simply by adding:
data: {
selected: 0,
options: ['Jan', 'Doe', 'Khan']
}
Your markup will be cleaner:
<select v-model="selected">
<option v-for="option in options" value="{{$index}}">{{option}}</option>
</select>
<br>
<span>Selected: {{options[selected]}}</span>
Here is the update JSFiddle
As th1rdey3 pointed out, you might want to use complex data and values couldn't simple be array's indexes. Still you can use and object key instead of the index. Here is the implementation.
You can use Cohars style or you can use methods too. Data is kept in options variable. The showText method finds out the selected values text and returns it. One benefit is that you can save the text to another variable e.g. selectedText
HTML:
<div id='app'>
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<br>
<span>Selected: {{ showText(selected) }}</span>
</div>
JAVASCRIPT:
var vm = new Vue({
el: '#app',
data: {
selected: 'A',
selectedText: '',
options: [{
text: 'One',
value: 'A'
}, {
text: 'Two',
value: 'B'
}, {
text: 'Three',
value: 'C'
}]
},
methods: {
showText: function(val) {
for (var i = 0; i < this.options.length; i++) {
if (this.options[i].value === val){
this.selectedText = this.options[i].text;
return this.options[i].text;
}
}
return '';
}
}
});
JSFiddle showing demo
I tried to use the following suggestion of MrMojoRisin's
v-bind:value="{ id: product.id, text: product.name }"
However for me this was resulting in that Object's toString() representation being assigned to value, i.e. [object Object]
What I did instead in my code was to call JSON.stringify on a similar object bound to the value:
v-bind:value="JSON.stringify({id: lookup[lookupIdFields[detailsSection]], name: lookup.Name})"
Then of course I can convert it back to an object using JSON.parse and get the requisite id and name values from the result
الفترة
اختر الفترة
{{ period.name }}
<label for="period_id" class="block font-medium text-sm text-gray-700">الفترة</label>
<select v-model="form.period_id" id="period_id" class="border-gray-300">
<option disabled value="">اختر الفترة</option>
<option v-for="period in periods" :value="period.id" :selected="building.period_id === period.id ? 'selected' : null">
{{ period.name }}
</option>
</select>
Outside of the template I access the name of the option like this:
let option_name = this.options[event.target.options.selectedIndex].name
To do this take this approach to set up your template:
Defined your options in an array like
[{"name":"Bar","value":1},{"name":"Baz","value":2}] ... etc
Put your options in the data function of the component
<script>export default {function data(){return { options }}}</script>
Load the options in the template using v:for:
<option v-for="option in options" v-bind:value="option.value">{{option.name}}</option>
Use #change="getOptionName" on the select element:
<select #change="getOptionName">
In your methods get the name:
getOptionName(event){ let option_name = this.options[event.target.options.selectedIndex].name }
Note in this case the object options in event.target.options does not have anything to do with your data named options ... hopefully that will avoid confusion
So a more advanced approach, but I believe when it is all set up correctly getting the name is not terrible, although It could be easier.
You can find it out in the Vue documentation here : http://vuejs.org/guide/forms.html#Select
Using v-model :
<select v-model="selected">
<option selected>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
In your case, I guess you should do :
<select name="customerName" id="" v-model="selected">
<option>Jan</option>
<option>Doe</option>
<option>Khan</option>
</select>
{{selected}}
Here is a working fiddle : https://jsfiddle.net/bqyfzbq2/
I think some of the answers here are a bit too complex, so I'd like to offer an easier solution. I'm only going to use an event handler in the example and leave out things like model binding, etc.
<select #change="yourCustomMethod">
<option value="1">One</option>
<option value="2">Two</option>
</select>
Then in your Vue instance:
...
methods: {
yourCustomMethod: function(event) {
var key = event.target.value, // example: 1
value = event.target.textContent; // example: One
}
}
...

OnChange event using React JS for drop down

var MySelect = React.createClass({
change: function(){
return document.querySelector('#lang').value;
},
render: function(){
return(
<div>
<select id="lang">
<option value="select" onChange={this.change}>Select</option>
<option value="Java" onChange={this.change}>Java</option>
<option value="C++" onChange={this.change}>C++</option>
</select>
<p></p>
<p value={this.change}></p>
</div>
);
}
});
React.render(<MySelect />, document.body);
The onChange event does not work.
The change event is triggered on the <select> element, not the <option> element. However, that's not the only problem. The way you defined the change function won't cause a rerender of the component. It seems like you might not have fully grasped the concept of React yet, so maybe "Thinking in React" helps.
You have to store the selected value as state and update the state when the value changes. Updating the state will trigger a rerender of the component.
var MySelect = React.createClass({
getInitialState: function() {
return {
value: 'select'
}
},
change: function(event){
this.setState({value: event.target.value});
},
render: function(){
return(
<div>
<select id="lang" onChange={this.change} value={this.state.value}>
<option value="select">Select</option>
<option value="Java">Java</option>
<option value="C++">C++</option>
</select>
<p></p>
<p>{this.state.value}</p>
</div>
);
}
});
React.render(<MySelect />, document.body);
Also note that <p> elements don't have a value attribute. React/JSX simply replicates the well-known HTML syntax, it doesn't introduce custom attributes (with the exception of key and ref). If you want the selected value to be the content of the <p> element then simply put inside of it, like you would do with any static content.
Learn more about event handling, state and form controls:
http://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
http://facebook.github.io/react/docs/forms.html
React Hooks (16.8+):
const Dropdown = ({
options
}) => {
const [selectedOption, setSelectedOption] = useState(options[0].value);
return (
<select
value={selectedOption}
onChange={e => setSelectedOption(e.target.value)}>
{options.map(o => (
<option key={o.value} value={o.value}>{o.label}</option>
))}
</select>
);
};
import React, { PureComponent, Fragment } from 'react';
import ReactDOM from 'react-dom';
class Select extends PureComponent {
state = {
options: [
{
name: 'Select…',
value: null,
},
{
name: 'A',
value: 'a',
},
{
name: 'B',
value: 'b',
},
{
name: 'C',
value: 'c',
},
],
value: '?',
};
handleChange = (event) => {
this.setState({ value: event.target.value });
};
render() {
const { options, value } = this.state;
return (
<Fragment>
<select onChange={this.handleChange} value={value}>
{options.map(item => (
<option key={item.value} value={item.value}>
{item.name}
</option>
))}
</select>
<h1>Favorite letter: {value}</h1>
</Fragment>
);
}
}
ReactDOM.render(<Select />, window.document.body);
handleChange(value, selectOptionSetter) => {
selectOptionSetter(value)
// handle other stuff like persisting to store etc
}
const Dropdown = (props) => {
const { options } = props;
const [selectedOption, setSelectedOption] = useState(options[0].value);
return (
<select
value={selectedOption}
onChange={e => handleChange(e.target.value, setSelectedOption)}>
{options.map(o => (
<option key={o.value} value={o.value}>{o.label}</option>
))}
</select>
);
};
If you are using select as inline to other component, then you can also use like given below.
<select onChange={(val) => this.handlePeriodChange(val.target.value)} className="btn btn-sm btn-outline-secondary dropdown-toggle">
<option value="TODAY">Today</option>
<option value="THIS_WEEK" >This Week</option>
<option value="THIS_MONTH">This Month</option>
<option value="THIS_YEAR">This Year</option>
<option selected value="LAST_AVAILABLE_DAY">Last Availabe NAV Day</option>
</select>
And on the component where select is used, define the function to handle onChange like below:
handlePeriodChange(selVal) {
this.props.handlePeriodChange(selVal);
}
I'll add this here, in case it helps someone because this was the solution that helped me.
This is to get the SELECTED INDEX. Not for the value.
(Worked for me because my options list was a list of numbers)
const [selectedOption, setSelectedOption] = useState(0)
<select onChange={event => setSelectedOption(event.target.options.selectedIndex)}>
Thank you Felix Kling, but his answer need a little change:
var MySelect = React.createClass({
getInitialState: function() {
return {
value: 'select'
}
},
change: function(event){
this.setState({value: event.target.value});
},
render: function(){
return(
<div>
<select id="lang" onChange={this.change.bind(this)} value={this.state.value}>
<option value="select">Select</option>
<option value="Java">Java</option>
<option value="C++">C++</option>
</select>
<p></p>
<p>{this.state.value}</p>
</div>
);
}
});
React.render(<MySelect />, document.body);
var MySelect = React.createClass({
getInitialState: function() {
var MySelect = React.createClass({
getInitialState: function() {
return {
value: 'select'
}
},
change: function(event){
event.persist(); //THE MAIN LINE THAT WILL SET THE VALUE
this.setState({value: event.target.value});
},
render: function(){
return(
<div>
<select id="lang" onChange={this.change.bind(this)} value={this.state.value}>
<option value="select">Select</option>
<option value="Java">Java</option>
<option value="C++">C++</option>
</select>
<p></p>
<p>{this.state.value}</p>
</div>
);
}
});
React.render(<MySelect />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Categories

Resources