onClick not working on options field - javascript

I have an array of countries
const countries = [{
name: 'United States', value: 'US', currency: 'USD'
}, {
name: 'Israle', value: 'IL', currency: 'ILS'
}, {
name: 'United Kingdom', value: 'UK', currency: 'GBP'
}]
And following code in react component
handleCountryChange(val){
console.log(val)
}
<select className="form-control input-lg" name="country" placeholder="Country" >
{ countries.map((val, index) => {
return(<option value={val.value} onClick={() => this.handleCountryChange(val)} key={index}>{val.name}</option>)
})}
</select>
but here my onClick is not being called... I want to get all the fields of the array inside the onClick function... How do I do it either with javascript or reactjs?
And onChange gives the event and targeted value not all the fields

You should put the handler on select element. Not on individual option.
Try the following..
<select className="form-control input-lg" name="country" placeholder="Country" onChange={(event) => this.handleCountryChange(event)}>
{ countries.map((val, index) => {
return(<option value={val.value} key={index}>{val.name}</option>)
})}
</select>

I made it by setting value as a index and then get the element by indexed value from the array
handleCountryChange(e){
this.setState({
country: countries[e.target.value].value,
currency: countries[e.target.value].currency
})
}
<select className="form-control input-lg" name="country" onChange={(e) => this.handleCountryChange(e)}>
{ countries.map((val, index) => {
return(<option value={index} key={index}>{val.name}</option>)
})}
</select>

Put the onChange handler on the select element instead.
Example
class App extends React.Component {
state = {
countries: [
{
name: "United States",
value: "US",
currency: "USD"
},
{
name: "Israle",
value: "IL",
currency: "ILS"
},
{
name: "United Kingdom",
value: "UK",
currency: "GBP"
}
]
};
handleCountryChange = event => {
const { value } = event.target;
const option = this.state.countries.find(
country => country.value === value
);
console.log(option);
};
render() {
const { countries } = this.state;
return (
<select
className="form-control input-lg"
name="country"
placeholder="Country"
onChange={this.handleCountryChange}
>
{countries.map((val, index) => {
return (
<option value={val.value} key={index}>
{val.name}
</option>
);
})}
</select>
);
}
}

Related

How to use onChange in multi-select react form?

In case of multi-select , can someone help me with the onChange function ?
What can I pass inside updateFormState( ) to make the code work. Thanks.
const formState = {
fruits: "",
};
function updateFormState(key, value) {
formState[key] = value;
}
const [fruits] = useState([]);
<Form.Label>fruits</Form.Label>
<MultiSelect
options={[
{ label: "Grapes 🍇", value: "grapes" },
{ label: "Mango 🥭", value: "mango" },
{ label: "Strawberry 🍓", value: "strawberry", disabled: true },
]}
id="fruits"
labelledBy="Select"
value={fruits}
onChange={(e) => updateFormState( )}
/>
</Form.Group>
hi try this i hope it usefull
const [fruits, setFruits] = useState();
console.log("fruits",fruits);
return (
<div>
<select onChange={(e) => setFruits(e.target.value)} value={fruits}>
<option value='' selected disabled hidden>
select a fruits
</option>
<option value='apple'>apple</option>
<option value='banana'>banana</option>
<option value='orange'>orange</option>
</select>
</div>
);

Select value doesnt change the first time I trigger onChange event when using setSate React

I have a set of select menus and I am trying to change a value when I select an option using onChange={updateValue} event. When I first select an option, the value is not being updated in the select menu.
It only changes the second time I try to choose an option. Not sure what I am doing wrong.
Edit: I did some more research (OnChange event using React JS for drop down) and I believe I need the value of the select to be updated as well, using setState. I cant figure out how to do it without having a variable for each value and set the state again.
let selectMenus = [
{
id: 'id1',
name: 'name1',
label: 'label1',
value: '0',
options: [
{
text: 'All ages',
value: '0',
},
{
text: '35 - 37 yrs',
value: '1',
},
],
buttonLabel: 'Refresh',
},
{
id: 'id2',
name: 'name2',
label: 'label2',
value: '1',
options: [
{
text: 'All ages',
value: '0',
},
{
text: '45 - 50 yrs',
value: '1',
},
],
buttonLabel: 'Refresh',
},
];
const [url, setUrl] = useState('http://localhost:5000/selectDropdowns1');
const updateValue = () => {
setUrl('http://localhost:5000/selectDropdowns2');
};
<form>
{selectMenus.map((select) => (
<div key={select.id} className='select-container'>
<label htmlFor={select.id}>{select.label}</label>
<select id={select.id} name={select.name} value={select.value} onChange={updateValue}>
{select.options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
<button>{select.buttonLabel}</button>
</div>
))}
</form>;
The problem is that when you provide onChange prop to select component it become a controlled component.
For more information: React Docs - Forms #controlled components
When you dealing with controlled components you must provide a value to it and when onChange triggerd it should update that value to work properly. Since you did not provide the full code, I imagine you have an array of select menus and options attached to it.
So in this case every select component should have own onChange method and own value to work properly. To achive this we should create another component for only Select Options. Like this;
function SelectComponent({ optionList, onSelected }) {
const [value, setValue] = useState();
const updateValue = ({ target }) => {
setValue(target.value);
if (onSelected) onSelected(target.value);
};
return (
<>
<label htmlFor={optionList.id}>{optionList.label}</label>
<select
id={optionList.id}
name={optionList.name}
value={value}
onChange={updateValue}
>
{optionList.options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
<button>{optionList.buttonLabel}</button>
</>
);
}
This component accepts to props; optionList and onSelected
optionList is the list of options to render
onSelected is a method that we call when user select and option
On main component, we should change the select section with our select component with props optionList and onSelected
return (
<div>
{selectMenus.map((select) => (
<div key={select.id} className="select-container">
<SelectComponent optionList={select} onSelected={updateValue} />
</div>
))}
</div>
);
So overall code is like this:
import { useState } from "react";
import { v4 as uuid } from "uuid";
export default function App() {
const [url, setUrl] = useState();
const updateValue = (value) => {
setUrl(value);
};
const selectMenus = [
{
id: 1,
label: "Menu 1",
name: "menu1",
buttonLabel: "Menu 1",
options: [
{
text: "option 1",
value: "option1"
},
{
text: "option 2",
value: "option2"
},
{
text: "option 3",
value: "option3"
}
]
},
{
id: 2,
label: "Menu 2",
name: "menu2",
buttonLabel: "Menu 2",
options: [
{
text: "option 1",
value: "option1"
},
{
text: "option 2",
value: "option2"
},
{
text: "option 3",
value: "option3"
}
]
},
{
id: 3,
label: "Menu 3",
name: "menu3",
buttonLabel: "Menu 3",
options: [
{
text: "option 1",
value: "option1"
},
{
text: "option 2",
value: "option2"
},
{
text: "option 3",
value: "option3"
}
]
}
];
return (
<div className="App">
<h1>URL Value: {url}</h1>
{selectMenus.map((select) => (
<div key={select.id} className="select-container">
<SelectComponent optionList={select} onSelected={updateValue} />
</div>
))}
</div>
);
}
function SelectComponent({ optionList, onSelected }) {
const [value, setValue] = useState();
const updateValue = ({ target }) => {
setValue(target.value);
if (onSelected) onSelected(target.value);
};
return (
<>
<label htmlFor={optionList.id}>{optionList.label}</label>
<select
id={optionList.id}
name={optionList.name}
value={value}
onChange={updateValue}
>
{optionList.options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
<button>{optionList.buttonLabel}</button>
</>
);
}
Working example is overhere codesandbox

How do you create an autocomplete input in Aurelia?

I am new to Aurelia, and am wondering how you can create an autocomplete input. I am trying to autocomplete for a panel of colors, and once you type into the input, it will autocomplete to the colors (items) that are in the panel.
This is the html:
<template>
<div>
<input type="text" value.bind="selectedColors1"
change.delegate="search()" id="filter" placeholder="Search for
feeds..">
<div>
<select multiple value.bind="selectedColors1" style="width:50%">
<option repeat.for="color of colors1" model.bind="color.id">
${color.name}
</option>
</select>
</div>
</div>
<br />
<button type="button" click.delegate="add()">Add</button>
<button type="button" click.delegate="remove()">Remove</button>
<br />
<select multiple value.bind="selectedColors2" style="width:50%">
<option repeat.for="color of colors2" model.bind="color.id">
${color.name}
</option>
</select>
</template>
And this is the JS:
export class dualList {
colors1 = [
{ id: "purple", name: "Purple" },
{ id: "black", name: "Black" },
{ id: "orange", name: "Orange" }
];
colors2 = [
{ id: "white", name: "White" },
{ id: "red", name: "Red" },
{ id: "blue", name: "Blue" }
];
selectedColors1 = [];
selectedColors2 = [];
add() {
this.selectedColors1.forEach(selected => {
// get the index of selected item
const index = this.colors1.findIndex(c => c.id === selected);
this.colors2.push(this.colors1[index]);
this.colors1.splice(index, 1);
});
}
remove() {
this.selectedColors2.forEach(selected => {
// get the index of selected item
const index = this.colors2.findIndex(c => c.id === selected);
this.colors1.push(this.colors2[index]);
this.colors2.splice(index, 1);
});
}
search(){
console.log(this.selectedColors1);
return true;
}
}
I expected the input id "filter" to autocomplete the colors in the first list, but nothing happens.

React select v2 on space press selects first value

When on Select field I hit space, first value from options is being selected. How to disable such behaviour?
<Select
ref={r => (this.selectRef = r)}
className="basic-single"
classNamePrefix="select"
onInputChange={val => {
console.log('va', val)
this.setState({ inputValue: val })
}}
inputValue={this.state.inputValue}
options={[{ value: 'aaa', label: 'aaa bbb' }, { value: 'bbb', label: 'bbb ccc' }]}
name="color"
/>
HERE IS A DEMO
I would suggest to use the onKeyDown props and prevent the action when the use hits the space bar so nothing will be selected.
<Select
ref={r => (this.selectRef = r)}
className="basic-single"
classNamePrefix="select"
onInputChange={val => {
this.setState({ inputValue: val });
}}
onKeyDown={e => {
if (e.keyCode === 32 && !this.selectRef.state.inputValue) e.preventDefault();
}}
inputValue={this.state.inputValue}
options={[
{ value: "aaa", label: "aaa bbb" },
{ value: "bbb", label: "bbb ccc" }
]}
name="color"
/>
Live example here.

Vue js populate new selects when changing the main one

I need your help about populating or loading new select with vue js, I know how to do this with jquery but in vue i don't know how because i'm new with this library.
i have the main select :
<select>
<option value='3'>FRANCE</option>
<option value='5'>USA</option>
<option value='6'>CANADA</option>
<option value='8'>MOROCCO</option>
</select>
I want that if i choose FRANCE i get a select of FRANCE cities from database, and also when i select USA i get an other select of USA cities from database.
So for example i will get :
<select>
<option value='6'>CANADA</option>
<option value='8'>MOROCCO</option>
</select>
<select>
<option value='34'>France city one</option>
<option value='35'>France city two</option>
</select>
<select>
<option value='3'>Usa city one</option>
<option value='5'>Usa city two</option>
</select>
When choosing France and USA i will populate select of cities with an array
I appreciate any help, I don't realy know how can i do this with vue js,
I don't want add all select of cities in my html because i don't know how much countries i have.
I tried this but this not resolve my probleme :
const addProduct = new Vue({
el: '#addProduct',
data: {
name: '',
name_url: '',
cities: '',
countries: [],
range: 0
},
created: function () {
this.$http.get('/api/countries').then(response => {
this.countries = response.data
}, response => {
});
},
methods: {
addForm: function(val, data) {
this.range += 1;
alert(this.range)
var index = _.findIndex(this.countries,{city_id: val});
this.countries.splice(index, 1)
}
},
watch: {
'cities' (val, oldVal) {
this.$http.post('/api/cities/values', {city_id:val}).then(response => {
this.addForm(val, response.data);
}, response => {
});
}
}
});
in html :
<div class="uk-grid" data-uk-grid-margin>
<div class="uk-width-medium-1-4">
<label for="attribute">Countries</label>
<md-select name="country" id="country" v-model="country">
<md-option v-for="country in countries" :value="country.country_id">#{{ country.name }}</md-option>
</md-select>
</div>
</div>
<div class="uk-grid" data-uk-grid-margin>
<my-cities v-for="n in range"></my-cities>
</div>
<script type="x-template" id="my-cities">
<div class="uk-width-medium-1-4">
<label for="attr">Cities</label>
<md-select name="attr" id="attr" v-model="attr">
<md-option value="">Select </md-option>
<md-option value="val in values">Select</md-option>
</md-select>
</div>
</script>
an example like this on Jsfiddle : http://jsfiddle.net/pu8pp62v/3/
This is an example that you can maybe use (but need some modifications to use your API call) :
new Vue({
el: "#app",
data: function() {
return {
selectedCountries: [],
selectOptionsCountries: [
{ value: 3, name: 'FRANCE' },
{ value: 5, name: 'USA' },
{ value: 6, name: 'CANADA' },
{ value: 8, name: 'MOROCCO' }
],
selectedCities: [],
selectOptionsCities: []
}
},
methods: {
},
watch: {
selectedCountries: function(newValue, oldValue) {
this.selectOptionsCities = [];
this.selectedCities = [];
for( var i = 0, length = newValue.length; i < length; i++ ){
this.selectedCities[i] = [];
if( newValue[i] === 3 ){
this.selectOptionsCities.push(
[{ value: 31, name: 'Paris' },
{ value: 32, name: 'Marseille' }]
)
}
if( newValue[i] === 5 ){
this.selectOptionsCities.push(
[{ value: 51, name: 'New-York' },
{ value: 52, name: 'Boston' }]
)
}
if( newValue[i] === 6 ){
this.selectOptionsCities.push(
[{ value: 61, name: 'Montreal' },
{ value: 62, name: 'Vancouver' },
{ value: 63, name: 'Ottawa' },
{ value: 64, name: 'Toronto' }]
)
}
if( newValue[i] === 8 ){
this.selectOptionsCities.push(
[{ value: 81, name: 'Rabat' },
{ value: 82, name: 'Casablanca' },
{ value: 83, name: 'Fes' }]
)
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.5/vue.js"></script>
<div id="app">
Selected countries : {{ selectedCountries }}
<br />
Selected cities : {{ selectedCities }}
<br />
<select v-model="selectedCountries" multiple>
<option v-for="(option, index) in selectOptionsCountries" :value='option.value'>
{{ option.name }}
</option>
</select>
<select v-for="(optionsCities, index) in selectOptionsCities" v-model="selectedCities[index]" multiple>
<option v-for="(option, index) in optionsCities" :value='option.value'>
{{ option.name }}
</option>
</select>
</div>
Added after author's comment:
Check this fiddle: http://jsfiddle.net/jjpfvx5q/1/
Inside 'chosenCities' array you have all selected cities by country (one city per country.)
Original answer:
Here is an example for you: fiddle
Is that what you are trying to achieve?
setTimeout functions are just pretending a real data fetching.
<script src="//unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<template>
<div>
<select v-model="country">
<option disabled value="">Please select one</option>
<option
v-for="c in countries"
:value="c.id">{{ c.name }}</option>
</select>
<span>Selected: {{ country }}</span>
<span v-if="cities.length">Cities:</span>
<ul v-if="cities.length">
<li v-for="c in cities">{{ c }}</li>
</ul>
</div>
</template>
</div>
<script>
var Main = {
data() {
return {
country: {},
countries: [],
cities: [],
coInit: [{ id: '3', name: 'France' }, { id: '2', name: 'USA' }],
cFrance: ['Paris', 'Whatever'],
cUSA: ['NY', 'LA']
}
},
methods: {
loadCountries: function () {
setTimeout(() => { this.countries = this.coInit }, 500);
},
getCities: function() {
if(this.country) {
switch (this.country) {
case '3':
setTimeout(() => { this.cities = this.cFrance }, 500);
break;
case '2':
setTimeout(() => { this.cities = this.cUSA }, 500);
break;
}
}
}
},
mounted() {
this.loadCountries();
},
watch: {
country: function() {
this.getCities();
}
}
}
var Ctor = Vue.extend(Main);
new Ctor().$mount('#app');
</script>

Categories