Retrieve selected values from multi-select box in vue js - javascript

I am having a hard time retrieving values from a multi-select box in Vue. After the user has selected any number of values, I want to retrieve the values and submit to a data source. No luck so far. Here's an excerpt of my code below.
<div id="app">
<select multiple v-bind:data-id="program.id" :disabled="!program.editable" v-model="program.dropDowns">
<option>Microsoft</option>
<option>IBM</option>
<option>Google</option>
<option>Apple</option>
</select>
</div>
getPrograms: function() {
axios.get("https://my-json-server.typicode.com/isogunro/jsondb/Programs").then((response) => {
this.programs = response.data.map(row => ({
...row,
dateFormatted: toDDMMYY(row.Date),
editable: false,
dropDowns: ["Apple","Google"]
}));
console.log(this.programs)
})
.catch(function(error) {
console.log(error);
});
}
Any help would be much appreciated. Here's the actual pen

The problem is that you are not passing anything to the saveItem function, so no program was being sent.
You just have to replace saveItem for saveItem(program) and that should do the trick.

Just you have assigned drop down data wrongly , Need to change like below:
Little change in template:
<button v-else #click="saveItem(program)">save</button>
and saveItem() method like below:
saveItem (program) {
program.isReadOnly = true
program.editable = false
console.log(program)
alert(program.dropDowns)
}

Related

Dynamic selection of 2nd item from a static dropdown using cypress

to automate CRUD functionality I need to select the 2nd item from a static drop down and the html is like
<select name="segment[segment_contact_id]" id="segment_segment_contact_id">
<option value="73082">Rita Basu</option>
<option value="73349">researcher user</option>
</select>
So by using cypress I am using the hardcoded value and my code is like
const segmentUser2 = 'researcher user'
const userValue2 = 73349
cy.get('select#segment_segment_contact_id')
.select(segmentUser2)
.should('have.value', userValue2)
I need suggestion because I don't like to use the hardcoded value instead I would like to use always the 2nd item from the drop down dynamically.
You could do something like this
Cypress.Commands.add(
'selectNth',
{ prevSubject: 'element' },
(subject, pos) => {
cy.wrap(subject)
.children('option')
.eq(pos)
.then(e => {
cy.wrap(subject).select(e.val())
})
}
)
Usage
cy.get('[name=assignedTo]').selectNth(2)
Here is #ItsNotAndy's way without the custom command.
cy.get('select#segment_segment_contact_id')
.children('option').eq(1)
.then($option => {
cy.wrap($option).parent().select($option.val())
})
As a function
function selectNth(selector, pos) {
cy.get(selector)
.children('option').eq(pos)
.then($option => {
cy.wrap($option).parent().select($option.val())
})
}
selectNth('select#segment_segment_contact_id', 1)
Verifying from text displayed
cy.get('select#segment_segment_contact_id')
.find(':selected')
.contains('researcher user')
Verifying by selectedIndex
cy.get('select#segment_segment_contact_id')
.its('0.selectedIndex')
.should('eq', 1)
You can use this as well. Here first we are getting value of the second item in the list using the eq() command. Then once we have got the value, we are just simply passing that to select().
cy.get('select#segment_segment_contact_id option').eq(1).invoke('val')
.then((val) => {
cy.get('select#segment_segment_contact_id').select(val)
})
And if you want to just validate the value or text you can do:
cy.get('select#segment_segment_contact_id option')
.eq(1).should('have.value', 73349)
cy.get('select#segment_segment_contact_id option')
.eq(1).should('have.text', 'researcher user')

antd design select placeholder issues

I am using antd design in my React app.
Here's a code snippet where I am facing the issues :
<Select
showSearch
optionFilterProp = "children"
placeholder = "Select Company"
value = "{this.state.company}"
name = "company"
onSelect = "{this.handleCompanyChange}"
>
Now it shows the correct value selected if this.state.company is not null. But if this.state.company is empty or null, placeholder doesn't shows up.
How can I solve this issue so that the placeholder appears if value is null?
set this.state.company to be undefined instead of null.
you should update as below:
<Select
showSearch
optionFilterProp = "children"
placeholder = "Select Company"
value = {this.state.company || undefined} ---- update this line
name = "company"
onSelect = "{this.handleCompanyChange}"
>
It should be set to undefined instead of null or "" empty string.
this.props.form.setFieldsValue({
myFieldName: undefined
})
I have faced the the same issue, heres the solution:
Code snippet for ant design select
<Select key="1" value={this.getStateValue()} showSearch allowClear placeholder='Select Weight' onChange={onWeightChange}>
{options}
</Select>
where getStateValue will be this:
getStateValue = () => {
const { value } = this.state;
if (value) {
return value;
}
}
I changed from:
const [value, updateValue] = useState("");
To:
const [value, updateValue] = useState(undefined);
And it worked!
If you are using Form.create() of the Antd then there is another cool way to set/get the value of the form. Note that in this method the components (Select and others) have to be inside a <Form> element. Also the enclosing class should be passed in Form.create() object as props, as shown below:
export default connect(mapStateToProps, mapDispatchToProps)(Form.create()(YourClassName));
This way we have this.props.form available in the props. This will have an important function named getFieldDecorator, as shown below:
const { getFieldDecorator } = this.props.form;
Every Input component must be wrapped inside a , see below:
<FormItem>
{ getFieldDecorator('prefix', {
initialValue: '86',
})(
<Select style={{ width: 70 }}>
<Option value="86">+86</Option>
<Option value="87">+87</Option>
</Select>
);}
</FormItem>
As you can see above, this is more easier way to set initial value to the form elements.
Note that at times when you need to set values of the form elements in functions programatically then you can use setFieldsValue, setFields etc.
Before using getFieldsValue getFieldValue setFieldsValue and so on, please make sure that corresponding field had been registered with getFieldDecorator.
Please refer https://ant.design/components/form/?locale=en-US#Form-fields for more information on coordinated controls.
Example:
componentDidMount() {
if (someCheckHere){
this.props.form.setFieldsValue({
company: userData.companyName
})
}
}
Check the image posted, you need to target the name and try to set it to null if its an empty string, this should work.

React Warning: flattenChildren(...): Encountered two children with the same key

Could someone please explain how to fix this error
Warning: flattenChildren(...): Encountered two children with the same
key
I have replicated my code below, but for some reason CodePen is not showing the error.
var FilterOptions = React.createClass({
changeOption: function(type, e) {
var val = e.target.value;
this.props.changeOption(val, type);
},
render: function() {
return (
<div className="filter-options">
<div className="filter-option">
<select id="product" name="Product" value={this.props.product} onChange={this.changeOption.bind(this, 'product')}>
<option value=''>Product</option>
{this.props.productOptions.map(function(option) {
return (<option key={option} value={option}>{option}</option>)
})}
</select>
</div>
</div>
);
}
});
Codepen
As a secondary question, I am pretty sure my reset is supposed to reset the values of the select boxes but this is also not working and just resetting the rendered results - not sure if this is related to the first problem?
Any help much appreciated
It is not a good idea to use the index as the key. A key is the only thing React uses to identify DOM elements. What happens if you push an item to the list or remove something in the middle? If the key is same as before React assumes that the DOM element represents the same component as before. But that is no longer true. From: https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
It is much better to use a unique string from each item you are mapping over as the key. Something like <option key={value.id}> or if a key does not exist, create a unique identifier by doing something like <option key={value.name + value.description}>.
Adding the index as value fixed this. Thanks #azium for your sugegstion.
<select id="product" name="Product" value={this.props.product} onChange={this.changeOption.bind(this, 'product')}>
<option value=''>Product</option>
{this.props.productOptions.map(function(option, value) {
return (<option key={value} value={option}>{option}</option>)
})}
</select>
I'm a big fan of using key by combining index with some constant value rather than using key={value.name + value.description}:
key={'some-constant-value'+index}
This is because I can pass the key knowingly which compoent is it for. For eg. <ComponentA key={'compoent-a-'+i} />. Also, I follow this approach is because simple html convention matches like we give id="my-some-of-the-id" or something.
So, even if you want to use name and description as the key, you may use like this rather:
key={'some-constant-'+value.name+'-'+value.description}
This is just an opinion. Though, I follow html convention when writing props value.
actually you need to specify to each children a unique key,so for that you need to create another key,for example if you are getting data from the database so for that create a new column for example (id) and then add value of that column to your div or what matter you are looping on as a key
var FilterOptions = React.createClass({
changeOption: function(type, e) {
var val = e.target.value;
this.props.changeOption(val, type);
},
render: function() {
return (
<div className="filter-options">
<div className="filter-option">
<select id="product" name="Product" value={this.props.product} onChange={this.changeOption.bind(this, 'product')}>
<option value=''>Product</option>
{this.props.productOptions && this.props.productOptions.map(function(option) {
return (<option key={option.id} value={option}>{option}</option>)
})}
</select>
</div>
</div>
);
}
});
i hope this help anyone in the future.

How to set default value on an input box with select2 initialized on it?

How do I set default value on an input box with select2? Here is my HTML:
<input type="text" id="itemId0" value="Item no. 1">
and my javascript:
$("#itemId0").select2({
placeholder: 'Select a product',
formatResult: productFormatResult,
formatSelection: productFormatSelection,
dropdownClass: 'bigdrop',
escapeMarkup: function(m) { return m; },
minimumInputLength:1,
ajax: {
url: '/api/productSearch',
dataType: 'json',
data: function(term, page) {
return {
q: term
};
},
results: function(data, page) {
return {results:data};
}
}
});
function productFormatResult(product) {
var html = "<table><tr>";
html += "<td>";
html += product.itemName ;
html += "</td></tr></table>";
return html;
}
function productFormatSelection(product) {
var selected = "<input type='hidden' name='itemId' value='"+product.id+"'/>";
return selected + product.itemName;
}
Here is the issue:
If I won't initialize my input box into a select2 box, I can display the default value of my input box which is "Item no. 1":
but when I initialize it with select2 eg. $("#itemId0").select2({code here}); I can't then display the default value of my text box:
Anyone knows how can I display the default value please?
You need to utilize the initSelection method as described in Select2's documentation.
From the documentation:
Called when Select2 is created to allow the user to initialize the selection based on the value of the element select2 is attached to.
In your case, take a look at the Loading Remote Data example as it shows how to incorporate it along with AJAX requests.
I hope this helps.
Old initial selections with initSelection
In the past, Select2 required an option called initSelection that was
defined whenever a custom data source was being used, allowing for the
initial selection for the component to be determined. This has been
replaced by the current method on the data adapter.
{
initSelection : function (element, callback) {
var data = [];
$(element.val()).each(function () {
data.push({id: this, text: this});
});
callback(data);
}
}
You can use the set value too.
You should directly call .val on the underlying element
instead. If you needed the second parameter (triggerChange), you
should also call .trigger("change") on the element.
$("select").val("1").trigger("change"); // instead of $("select").select2("val", "1");
Refs:
https://select2.github.io/announcements-4.0.html
https://github.com/select2/select2/issues/2086
http://jsfiddle.net/F46NA/7/
If you have an input element, declare it as follows. Remember to populate the value field as well.
<input type="hidden" name="player" id="player" data-init-text="bla bla" value="bla bla" >
Write an initSelection function
initSelection : function (element, callback) {
var elementText = $(element).attr('data-init-text');
callback({"text":elementText,"id":elementText});
}
make sure that this call back has same key value pair as the one return by the ajax call.
callback({"text":elementText,"id":elementText});
I have noticed that keeping the value field empty will keep the input empty by default so remember to populate it as well.
The method initSelection can not have an empty value attribute to work properly.
That was my problem.
Hopefully this will help someone.
You can easily change the value of your select input by just putting the id's of your selected option in data attribute of your select input. And then in javascript
var select = $('.select');
var data = $(select).data('val');
$(select).val(data);
And after that initialize select2 on your select input
$(select).select2();
Here is the fiddle https://jsfiddle.net/zeeshanu/ozxo0wye/
you dont need ajax or json, you just need to put SELETED tag into your OPTION and SELECT2 will display the init value.
This works for me: 'Add default value to the head of array'
data.unshift({'id':-1, 'name':'xxx'});
$('#id_xxx).select2({
placeholder: '--- SELECT ---',
data: data,
allowClear: true,
width: '100%'
});
However, official doc says:
You can set default options by calling $.fn.select2.defaults.set("key", "value").
There is no example though.
I found the extremly simple solution.
You have to pass the ID and the Name of the default option and insert it like HTML inside
var html = ' <option value="defaultID">defaultName</option>';
$(".js-example-basic-single").html(html);
How to get defaultID or defaultName depends on your code.
For instance in ASP .Net MVC you can do it like
<select id="PersonalID" class="js-example-basic-single form-control form-control-sm" name="PersonalID">
<option value="#Model.PersonalID">#ViewBag.PersonalInfo</option>
</select>
I use another approach in this specific configuration:
- multiple="multiple"
- populating from AJAX on user's search
$("#UserID").select2({
placeholder: 'Input user name',
"language": {
"noResults": function () {
return "Sorry, bro!";
}
},
dropdownParent: $("#UserID").parent(),
ajax: {
delay: 200,
url: '#Url.Action("GetUserAsJSON", "AppEmail")',
cache: true,
dataType: 'json',
data: function (params) {
var query = {
search: params.term,
page: params.page || 1
};
// Query parameters will be ?search=[term]&page=[page]
return query;
}
}
});
There are few steps to get working my solution
1) Keep each added value in a global array.
var selectedIDs = new Array();
$("#UserID").on('change', function (e) {
//this returns all the selected item
selectedIDs = $(this).val();
});
2) So when you save data you always have selectedIDs array.
3) When you refresh/load webpage just populate selectedIDs with saved data for later resaving/editing from one hand and from another hand populate select2 object
In my case of ASP MVC it looks like this but you can use JQuery to insert <option> to <select>.
<select id="UserID" class="js-example-basic-multiple form-control border" name="UserID" style="width:100%!important;" multiple="multiple">
foreach (var item in Model.ToUsers)
{
<option selected="selected" id="#item.ID" value="#item.ID">#item.Value</option>
}
</select>

Dynamic data collection with Select2 and Meteor.js?

I have set up a collection as the source for my data in a Select2 multiple select as so:
<template name="mySubjectsSelector">
<div>
<select id="mySubjects" data-placeholder="Choose your subjects" multiple>
{{#each subjects}}
<option>{{this.name}}</option>
{{/each}}
</select>
</div>
</template>
And the .js:
Template.mySubjectsSelector.subjects = function () {
console.log("Fetching subjects...");
return Subjects.find({}).fetch();
};
Template.mySubjectsSelector.rendered = function () {
console.log("mySubjectsSelector is rendered!");
$('#mySubjects')
.select2({
width: "300px"
});
};
Whenever the Subjects collection is updated, it reactively re-renders the template, and that is fine, that's how I want it to behave. The unwanted behaviour, is that it will select the first option in the list when it is re-rendered, on ALL clients!
How can I avoid the selecting of the first item when it reloads/rerenders?
What I did is create a blank first option.
<template name="mySubjectsSelector">
<div>
<select id="mySubjects" data-placeholder="Choose your subjects" multiple>
<option></option>
{{#each subjects}}
<option>{{this.name}}</option>
{{/each}}
</select>
</div>
</template>
There's probably a smarter way of doing this, but it worked for me.
EDIT:
The more involved, Meteor-specific technique I have used to preserve values of the Select2 controls, by storing the values in a Session variable. Something like this:
Template.template.rendered = function () {
// assumes 1) all Select2 controls are originally <select> tags
// and 2) all Select tags have ids assigned
$('select').each(function (i) {
if (Session.get('preserve-' + this.id)) {
$(this).val(Session.get('preserve-' + this.id));
}
});
$('.select2').select2({ /* select2 code here */ })
.on('change', function (e) {
if (e.val !== "") {
Session.set("preserve-" + e.target.id, e.val")
}
});
};
However: I may have not understood the question exactly. If you are only asking how using Select2 to allow unselected answers, try a placeholder and allowclear. From the docs:
$("#e2").select2({
placeholder: "Select a State",
allowClear: true
});
Have you tried specifying a rule to preserve the <select> and <option> elements?
Template.mySubjectsSelector.preserve({
'select[id]': function (node) { return node.id; },
'option': function (node) { return node.id; }
});
Also see the documentation.
Another problem could be that the <option> elements don't have ids. Also from the documentation:
By default, new Meteor apps automatically include the preserve-inputs
package. This preserves all elements of type input, textarea, button,
select, and option that have unique id attributes or that have name
attributes that are unique within an enclosing element with an id
attribute. To turn off this default behavior, simply remove the
preserve-inputs package.

Categories