How to use FormControl for multiselect using react-bootstrap? - javascript

I am new to reactjs. I am trying to use multi select using form control.
Below is my code:
handleIds(e){
let id = null;
if(e.target.value) {
id = parseInt(e.target.value, 10);
} else {
id = null
}
this.state.Ids.push(id);
}
<FormGroup controlId="formQueryIds"
validationState = {this.validateNotEmpty(this.state.queryIds)}>
<ControlLabel>Query Ids</ControlLabel>
{this.loadQueries()}
<FormControl componentClass="select"
placeholder="Select ids"
onChange={this.handleIds}
multiple>
{this.state.items.map((item) => <option key={item.id}>{item.id}</option>)}
</FormControl>
<FormControl.Feedback />
</FormGroup>
Here items is an array of ids which is dynamically providing the option values.
The problem here is: for every single selection of option, it's triggering handleIds and adding the value to the array Ids[].
But when we unselect the option which we selected already, I am unable to trigger handleIds and remove the value from the array.
Is there a way to design to remove value from the array as soon it's unselected or instead of triggering handleIds for every selection, just triggering once and provide all the selected values as an array?

Related

search for item in long dropdown list with input filter, but only allow user to submit options from dropdown

I have a really long list in dropdown in my code (over3k+ options). Since my dropdown was so long I decided to use a datalist so the user can filter the dropdown easier with an input. This way they do not have to scroll through all 3k options.
I want to make it so the user can filter it, but CAN NOT enter/use a value that is not in the dropdown. I.E The input value will be an option from the dropdown or nothing. I'm not sure how to do this.
For instance they can type the colour John, but once they leave the input since John is not in the dropdown and they did not select it from the dropdown the value will be empty once they hit submit. However if they search blue and click blue, the input value will still be blue since it's in the datalist dropdown options.
Thanks in advance.
<form method = "POST">
<input class="form-control" type="text" id="color" list="colors_data" autocomplete = "off">
<datalist id="colors_data"style = "width:800px">
<option value="red"></option>
<option value="orange"></option>
<option value="green"></option>
<option value="blue"></option>
</datalist>
<input type = "submit" value = 'send_request'>
</form>
Grab an array of all the colours from the option values and check if your input value is included.
// Cache the elements
const options = document.querySelectorAll('option');
const form = document.querySelector('form');
const input = document.querySelector('#color');
const submit = document.querySelector('[type="submit"]');
// Add an click listener to the submit button
submit.addEventListener('click', handleSubmit, false);
// Iterate over the options with `map` and return a
// new array of colour values
const colors = Array.from(options).map(el => el.value);
function handleSubmit(e) {
// Prevent the form from submitting
e.preventDefault();
// Check to see if the input value is included
// in the colours array
if (colors.includes(input.value)) {
// If it is submit the form
console.log('Found');
// form.submit();
} else {
// Otherwise do nothing
console.log('Not found');
}
}
<input class="form-control" type="text" id="color" list="colors_data" autocomplete="off">
<datalist id="colors_data" style="width:800px">
<option value="red"></option>
<option value="orange"></option>
<option value="green"></option>
<option value="blue"></option>
</datalist>
<input type="submit" value='send_request'>
Note, if you didn't want to write out all that HTML you could build the options programmatically using an array, and using template strings to create the markup. Then you don't have to grab a separate array of colours to check against because you already have one.
const colors = ['red', 'orange', 'green', 'blue'];
// Iterate over the colour array to produce an array of strings
// that you then join into one string
function getOptions(arr) {
return arr.map(el => `<option value=${el}>${el}</option>`).join('');
}
// Grab the datalist element
const datalist = document.querySelector('datalist');
// And insert the options
datalist.insertAdjacentHTML('beforeend', getOptions(colors));
<datalist />
Additional documentation
Template literals
map and join
Array.includes and Array.from
querySelectorAll and querySelector
addEventListener and preventDefault

Bind the Selected option text To Input box

Im new to react, Im acheiving to search the text,which will post to the api, and the results will be displayed as options in box,for which im using twitter bootstrap just the className's to match with REACT.I want to make the make the option's value to be bind to the input text box above, if i select the option. How to achieve this using useRef and at the same time ,the select box should close if the option is selected.The HandleCHange for the input box triggers the api call for every keystrole
Below is the code for the select box.
<input
className='form-control'
placeholder='Search Drug...'
onChange={handleChange}
/>
<select class='custom-select' size={drugList.drugs?.length> 0 ? '10' : ''} onChange={handleSelectChange}>
{drugList.drugs?.length > 0 &&
drugList.drugs.map((each,index) => {
return (
<option key={index} value={`${each.drug}`}>
{each.drug}
</option>
)
})}
</select>
Here i want the selected value to be bind to the input box.It will be great if you give the sample code or snippet.
Please refer the image above.Thanks in Advance!
I want to make the make the option's value to be bind to the input text box above
---> use component state to store the selected value from the options dropdown
at the same time ,the select box should close if the option is selected.
----> hide/display select options based on input box focus by toggling component state.
created a sandbox for your app, please check
I think you can do this like this.
handleSelectChange = (event) =>{
this.setState({selectvalue:event.target.value});
}
handleChange= (event) =>{
this.setState({selectvalue:event.target.value});
---- and your code here---
}
<input
className='form-control'
placeholder='Search Drug...'
onChange={this.handleChange}
value={this.state.selectvalue}
/>
<select class='custom-select' size={drugList.drugs?.length> 0 ? '10' : ''} onChange={this.handleSelectChange}>
{drugList.drugs?.length > 0 &&
drugList.drugs.map((each,index) => {
return (
<option key={index} value={`${each.drug}`}>
{each.drug}
</option>
)
})}
</select>

Get last clicked element in multiple select Angular

Im trying to get the last clicked option in a multiple select, no matters if the option is selected or unselected.
The problem is that the select is not via template, is mounted dinamically via TS.
I've tried adding vanilla JS event listeners at the creation of the options but doesn't works. Actually i can get all the selected elements, but i lost the unselected option and i can't get exactly the new selected one.
My HTML
<tr *ngFor="let communityLine of communityLines">
<td>{{communityLine.name}}</td>
<td>{{communityLine.instrument.name}}</td>
<td>{{communityLine.param.name}}</td>
<td>{{communityLine.contextSource.name}}</td>
<td>{{communityLine.sampleType.name}}</td>
<td>{{communityLine.value}}</td>
<td>
<select multiple [id] ="communityLine.apiKey" (change)="eventGetChange(communityLine, $event)" [(ngModel)]="nodeKey">
</select>
</td>
</tr>
My TS function
private eventGetChange(commLineKey, event) {
console.log(this.nodeKey);
console.log(commLineKey);
console.log(event.target.value)
My TS method to mount the select, is a bit complicated because i need to show all nodes (stored in this.allNodes var) but select the nodes that are in other array (nodesInRelation var).
private mountSelect(nodesInRelation: Node[], lineApiKey: String): void {
let select = <HTMLSelectElement>document.getElementById(lineApiKey);
let copy = this.allNodes;
for (let node of nodesInRelation) {
copy.forEach((item, index) => {
if (item.name === node.name) copy.splice(index, 1);
});
}
for (let node of nodesInRelation) {
let newoption = new Option(node.name, node.apiKey, null, true);
select.add(newoption);
}
for (let node of copy) {
let newoption = new Option(node.name, node.apiKey, null, false);
select.add(newoption);
}
M.updateTextFields();
M.AutoInit();
}
In eventGetChange function first console.log i get all the current selected values, in the second i get the key and is okey and in the third i get only the first selected element in the box.
I just want the last clicked, selected or unselected.
Thanks you.
You seem to be ditching Angular and opting for direct DOM manipulation for no apparent reason. Angular is perfectly capable of populating options list programmatically. It could look something like
<td>
<select multiple [id] ="communityLine.apiKey" [(ngModel)]="nodeKey">
<option *ngFor="let option of optionList; let i = index"
[value]="option" (click)="eventGetChange(option)">{{ option }}
</option>
</select>
</td>
optionList: any[];
private mountSelect(nodesInRelation: Node[], lineApiKey: String): void {
// populate optionList here
}
private eventGetChange(commLineKey) {
// the clicked option is available here
}
If this.nodeKey as you say stores an array with all the current selected values you can simply do this:
this.nodeKey[this.nodeKey.length - 1]
It will give you the las value in the nodeKey array

How to get an input field when the user selects "Other" in a dropdown

I'm making a form and I want the user to see an input field when they select "Others" in the dropdown.
I'm fairly new to React and was trying to get the value itself from the input field, but it's not working.
<FormItem>
<h4 className={ 'register_form_title'}><span className={ "red_astrick_sign"}>*</span>Entity type</h4>
<Select placeholder="Type of entity" onChange={value=> setFieldValue('organisation_type', Number(value))} name="organisation_attributes.organisation_type">
<Option value="1">Public Limited Company</Option>
<Option value="2">Private Limited Company</Option>
<Option value="3">One Person Company</Option>
<Option value="4">Limited Liability Partnership</Option>
<Option value="5">Partnership Firm</Option>
<Option value="6">Sole Proprietorship</Option>
<Option value="0">Others</Option>
</Select>
</FormItem>
This is a simple dropdown which converts the chosen value to a number, so the output of the code will be {"organisation_type":<value>}. But if they select "Others", the input field should determine the <value>.
Use state to store the current value of the drop-down and visibility of input-field.
Inside the onChange handler, only set current value with the transformation when the value is not O(for Others) and set input-visibility to false. But, when it is 0, set input-visibility to true.
Inside the onChange of input field, set current value as would do.
Use a state variable to track visibility of input field.
constructor(props) {
super(props);
this.state = {show_input_field: false}
}
In your onChange attribute, check if the value is 0, setState of show_input_field to true, else false, hence showing/hiding the input field.
Using the same name attribute lets you save value in the desired 'organisation_attributes.organisation_type': <value> pair.
render() {
const {show_input_field} = this.state;
...
<Select placeholder="Type of entity" onChange={value => {
setFieldValue('organisation_attributes.organisation_type', Number(value));
if (value === 0)
this.setState({show_input_field: true});
else
this.setState({show_input_field: false});
}} name="organisation_attributes.organisation_type">
</Select>
{show_input_field ? <Input name="organisation_attributes.organisation_type" onChange={handleChange}/> : ""}
...
}
Hope this helps.

VueJS Component with datalist not showing options

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.

Categories