The Issue
I am trying to convert form inputs to a json object but having difficulty trying to achieve this, below is a snippet of the HTML which I have and the JSON which I'm trying to get.
{
"2019-01-23": [
{
id: 1,
period: 'am'
},
{
id: 2,
period: 'pm'
}
]
}
<select name="dates[2019-01-23][0][id]">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<select name="dates[2019-01-23][0][period]">
<option selected>am</option>
<option>pm</option>
</select>
<select name="dates[2019-01-23][1][id]">
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3">3</option>
</select>
<select name="dates[2019-01-23][1][period]">
<option>am</option>
<option selected>pm</option>
</select>
What I've tried
var inputs = $(':input').serializeArray();
var json = [];
$.each(inputs, function(key, input) {
var names = input.name.split(/\[(.*?)\]/);
var data = [];
data[names[1]] = [];
data[names[1]][names[3]] = { id: null, period: null };
if(names[5] == 'id') {
data[names[1]][names[3]].id = input.value;
}
if(names[5] == 'period') {
data[names[1]][names[3]].period = input.value;
}
json.push(data);
});
But this doesn't quite achieve what I'm after (multiple of the same date) and I'm getting a bit lost now, I'm sure there must be a way of doing this a lot easier.
First, match is more appropriate for your case than split.
Furthermore, since json is object literal, it should be initialised with empty object ({}), not array.
push is not quite appropriate for your case. It's better to use direct assignment instead.
So the code might look like this:
var inputs = $(':input').serializeArray();
var json = {};
$.each(inputs, function(key, input) {
var keys = input.name.match(/([^\[\]]+)/g).slice(1);
var date = keys[0], i = keys[1], id = keys[2];
if (!json[date]) json[date] = [];
if (!json[date][i]) json[date][i] = {};
json[date][i][id] = input.value;
});
console.log(JSON.stringify(json));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<select name="dates[2019-01-23][0][id]">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<select name="dates[2019-01-23][0][period]">
<option selected>am</option>
<option>pm</option>
</select>
<select name="dates[2019-01-23][1][id]">
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3">3</option>
</select>
<select name="dates[2019-01-23][1][period]">
<option>am</option>
<option selected>pm</option>
</select>
Related
I have a select with options and values:
<select id="sid">
<option value="sValue1">sText1</option>
...
</select>
I need to create an associated array for all pairs:
var data = {"sText1":"sValue1",...};
Is there ready/simplifies tools to do that?
It's a basic for ... on ... iteration.
Take note that if there are multiple <option> with the same label, the last one will take place in the result object.
const select = document.getElementById('sid');
const objContainer = document.getElementById('sid-obj');
const options = select.getElementsByTagName('option');
const selectObj = {};
for (const opt of options) {
let optObj = {};
optObj[opt.textContent] = opt.value;
Object.assign(selectObj, optObj);
}
// print result in code
objContainer.textContent = JSON.stringify(selectObj);
<select id="sid">
<option value="">Default</option>
<option value="sValue1">sText1</option>
<option value="sValue2">sText2</option>
<option value="sValue3">sText3</option>
<option value="sValue4">sText4</option>
<option value="sValue5">sText4</option>
</select>
<h2>Result:</h2>
<code id="sid-obj" />
Add a function to the select which will be called on change and on change get the value and the text from the selected option
function getValue(elem) {
let obj = {};
obj[elem.options[elem.selectedIndex].text] = elem.value
console.log(obj)
}
<select id="sid" onchange='getValue(this)'>
<option value="sValue1">sText1</option>
<option value="sValue2">sText2</option>
<option value="sValue3">sText3</option>
</select>
Sorry for being late to the party but here is a jQuery solution for the same.
var arr = {};
$("#sid option").each(function() {
let text = $(this).text();
arr[text] = $(this).val();
});
// print result
$('#sid-obj').append(JSON.stringify(arr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="sid">
<option value="">Default</option>
<option value="sValue1">sText1</option>
<option value="sValue2">sText2</option>
<option value="sValue3">sText3</option>
<option value="sValue4">sText4</option>
<option value="sValue5">sText4</option>
</select>
<h2>Result:</h2>
<code id="sid-obj" />
I dynamically generate additional forms on a page using Django Model Formsets. The user can generate as many forms as they need. This is done in a Vuejs method.
My issue is changing the options of the second select of the form that the first select value was chosen. I was thinking about trying on focus or on click to get the select that was last changed, but I'm not sure how that would work.
I do track the current count of forms on the page.
In the example below. If the user changed form_select_0 to One, I need form_subselect_0 to only have options C and D, but the selects in form_1 should not be altered.
Example:
<form id = form_0>
<select id="form_select_0">
<option value="one">One</option>
<option value="two">Two</option>
</select>
<select id="form_subselect_0">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>
</form>
<form id = form_0>
<select id="form_select_1">
<option value="one">One</option>
<option value="two">Two</option>
</select>
<select id="form_subselect_1">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>
</form>
Follow-up:
Added vue method (below) for how I'm currently adding Vuejs models to the Django Model Formsets. Question: Is there a better way?
addForm: function () {
this.count++
let form_count = this.count
form_count++
let formID = 'id_form-' + this.count
incremented_form = this.vue_form.replace(/form-\d/g, 'form-' + this.count)
this.formList.push(incremented_form)
this.$nextTick(() => {
let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
(function (ele, idx) {
ele.value = form_count
})
})
},
As stated above this was my final answer due to no response:
addForm: function () {
this.count++
let form_count = this.count
form_count++
let formID = 'id_form-' + this.count
incremented_form = this.vue_form.replace(/form-\d/g, 'form-' + this.count)
this.formList.push(incremented_form)
this.$nextTick(() => {
let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
(function (ele, idx) {
ele.value = form_count
})
})},
I am trying to save the values of multiple multi selects as one object ...
Here is what I am trying to do. I have 3 select boxes and am using the ChosenJS library for better ui.
All 3 multi-selects are using the same model (should this change?)
HTML
<div id="app">
<select multiple v-chosen v-model="choices" name="filters1" id="filters1">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
<select multiple v-chosen v-model="choices" name="filters2" id="filters2">
<option value="4">Option 4</option>
<option value="5">Option 5</option>
<option value="6">Option 6</option>
</select>
<select multiple v-chosen v-model="choices" name="filters3" id="filters3">
<option value="7">Option 7</option>
<option value="8">Option 8</option>
<option value="9">Option 9</option>
</select>
<pre>
Selected Options: {{choices}}
</pre>
</div>
JS
Vue.directive('chosen', {
twoWay: true,
bind: function () {
return this.vm.$nextTick((function (_this) {
return function () {
return $(_this.el).chosen({
inherit_select_classes: false,
width: '100%'
}).change(function (ev) {
var i, len, option, ref, values;
if (_this.el.hasAttribute('multiple')) {
values = [];
ref = _this.el.selectedOptions;
for (i = 0, len = ref.length; i < len; i++) {
option = ref[i];
values.push(option.value);
}
console.log(values);
return _this.set(values);
} else {
return _this.set(_this.el.value);
}
});
};
})(this));
},
update: function (nv, ov) {
return $(this.el).trigger('chosen:updated');
}
});
var app = new Vue({
el:'#app',
data: {
choices: []
}
})
My expected outcome would be:
Selected Options: ['2','3','6','8']
Is this possible?
I created a fiddle to show where I am at.
http://jsfiddle.net/tyLa562h/3/
No, you can't. Only radio buttons and checkboxes can have same model. So, here what you can do it by using a computed option: (choice1, choice2, choice3 are all three different model)
computed: {
allChoices: function() {
return this.choice1 + this.choice2 + this.choice3; // return how you want
}
}
You can even use getter/setter method if you want.
I'm trying to get the value of the option which have the attribute "selected" to compare it to the current option selected.
function onChangeOption(opt) {
var update_value = opt.value;
var selectedValue = '???'; // get selected attribute
if (update_value != selectedValue) {
// Do some things
}
}
<select class="form-control" onchange="onChangeOption(this)">
<!-- I wanna got the content of option selected=selected-->
<option selected="selected" value="1">1</option>
<option value="2">2</option>
</select>
// save initial selected value to a variable
var initSelected = $('.form-control option:selected').val();
$('select').on('change', function() {
// check if the selected value is the same as the initial one was
if(this.value == initSelected) {
console.log('same values');
} else {
console.log('not same values');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="form-control">
<option selected="selected" value="1">1</option>
<option value="2">2</option>
</select>
Just add change event listener.And get the selected value.You can achieve comparision between selected value and changed value by maintaining an array.Like below.
values = []//creates an array
select = document.querySelector('#myselect');
values.unshift(select.value);
//console.log(values);
select.addEventListener('change',function(){
update_value = this.value;
console.log(this.value);
if (update_value != values[0]) {
// alert('Not matched');
console.log('Not matched');
}
else{
//alert('Matched');
console.log('Matched')
}
});
<select class="form-control" id="myselect">
<option selected="selected" value="1"> 1 </option>
<option value="2"> 2 </option>
</select>
I think alexis actually wants something more like this:
function onChangeOption(opt) {
var update_value = opt.value;
var options = document.getElementsByTagName("option");
if (options[0].getAttribute("selected")=="selected") {
var selectedValue = options[0].value;
} else {
var selectedValue = options[1].value;
}
if (update_value != selectedValue) {
// If the selected option's value is not equal to the value of the option with the attribute "selected", then do... (this way, you can change the attribute to any of the options!)
console.log(selectedValue);
}
}
<select class="form-control" onchange="onChangeOption(this)">
<option selected="selected" value="1">1</option>
<option value="2">2</option>
</select>
Comment the result and if you need anything else. Glad to help.
You can always store previously selected values, if you want to access them somehow later on: working example.
HTML:
<select id="mySelect" class="form-control" onchange="onChangeOption(this)">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<p>Previous: <span id="prev"></span></p>
<p>Current: <span id="curr"></span></p>
JS:
var selectElem = document.getElementById("mySelect");
var prev = document.getElementById("prev");
var curr = document.getElementById("curr");
var allEverSelected = [ selectElem.value ];
selectElem.addEventListener("change", function(evt){
allEverSelected.push( this.value );
prev.innerHTML = allEverSelected[allEverSelected.length - 2];
curr.innerHTML = allEverSelected[allEverSelected.length - 1];
});
To access default value, just get the <select> value after DOM loads.
selected attribute on <option> tag exist only to make other than first <option> element inside <select> default option, i.e.:
<select>
<option value="1">1</option>
<option selected value="2">2</option>
</select>
Above select's default value is 2.
I think this is the one what you want. Try it.
function onChangeOption(opt) {
var update_value = opt.value;
console.log(update_value);
var selectedValue;// = '???'; // get selected attribute
// I think this is the one you want
//If you want to select the HTML element,
selectedValue=document.querySelector("option[value='"+update_value+"']");
console.log(selectedValue);
//
if (update_value != selectedValue) {
// Do some things
}
}
//onChangeOption(document.querySelector('form'));
function start(){
while(typeof document.querySelector('form')!=typeof {}){}
onChangeOption(document.querySelector('.form-control'));
}
<body onload="start()">
<select class="form-control" onchange="onChangeOption(this)">
<option selected="selected" value="1">1</option>
<!-- I wanna got this -->
<option value="2">2</option>
</select></body>
I have have following selections:
<select id="custom-headers" multiple="multiple" class="searchable custom-headers">
<option data-invoice-number="36655" value="1187">RAPCY3</option>
<option data-invoice-number="87172" value="1188">1188</option>
<option data-invoice-number="79190" value="1189">CXETHD</option>
<option data-invoice-number="24584" value="1190">ZDAC2X</option>
<option data-invoice-number="49694" value="1191">2T8SRJ</option>
<option data-invoice-number="11290" value="1192">XDCH5J</option>
<option data-invoice-number="96188" value="1193">83EYS8</option>
<option data-invoice-number="33819" value="1194">WE5PEW</option>
<option data-invoice-number="56529" value="1195">CJEQWM</option>
<option data-invoice-number="55643" value="1196">RAPCY3</option>
<option data-invoice-number="72334" value="1197">1197</option>
<option data-invoice-number="14563" value="1198">CXETHD</option>
<option data-invoice-number="58963" value="1199">ZDAC2X</option>
<option data-invoice-number="44810" value="1200">2T8SRJ</option>
<option data-invoice-number="88482" value="1201">XDCH5J</option>
<option data-invoice-number="9731" value="1202">83EYS8</option>
<option data-invoice-number="41170" value="1203">WE5PEW</option>
<option data-invoice-number="1911" value="1204">CJEQWM</option>
</select>
I need to gather up both the values and invoice-number into one array..
jQuery works fine only for Reslist:
o.reservations = [];
$('.custom-headers option:selected').each(function (i, selected) {
o.reservations[i] = $(selected).val();
});
Giving me back an array of 1187, 1188, 1189 i need something like
reslist => 1187, 1188, 1189, invoices => 36655, 87172, 79190
Tried:
o.reservations = [];
$('.custom-headers option:selected').each(function (i, selected) {
o.reservations[i] = $(selected).val();
o.reservations[i] = $(selected).data('invoice-number');
});
Not sure how to define the keys in js?
$('.custom-headers option:selected').each(function (i, selected) {
o.reservations.push({
value: $(selected).val(),
number: $(selected).data('invoice-number')
});
});
This will populate the following array:
[{value: 1187, number: 36655}, {value: 1188, number: 87172}, ...]
var arr = {"reslist":[], "invoices":[]};
$('.custom-headers option:selected').each(function (i, selected) {
arr.reslist.push($(this).val());
arr.invoices.push($(this).data("invoice-number"));
});
Use map.
console.log($('#custom-headers option').map(function(option){
var $this = $(option);
return { invoice-number: $this.data('invoice-number'), value: $this.val() };
}));