I have applied the logic in view.jsp in Liferay to show the state list on State drop down based on the Country selected from the Country drop down. I have used html and java script to achieve this goal of showing the state drop down for the selected country from drop down list. Currently, when I first load the form, both of the Country and the state label with drop down is displaying. The state drop down is empty at first. Then when I select country, Example: USA, state drop down is changed to the state list related to USA which is working as expected. But, I want to not show the state drop down and State label at first when form is loaded as it will be empty and there will be "Select Country" option only selected in Country drop down. This is not working for me. Any idea what should I do to make State label and drop down to show at first when form loads and just to show state drop down list only when the country is selected from Country drop down?
Below is the html and java script code that I have:
<select name="<portlet:namespace/>Country" id="countryId" onchange="javascript:countryChange()">
<option value="0">Select Country</option>
<option value='US'>United States</option>
<option value='CA'>Canada</option>
</select>
<label id="stateLabel">State:</label>
<select name="<portlet:namespace/>State" id="stateId">
</select>
<!--Country and State Change Javascript-->
<script>
function CountryChange() {
var countryState = [
[
'US', [
['', 'State/Province'],
['AL', 'Alabama'],
['AK', 'Alaska'],
['AZ', 'Arizona'],
['AR', 'Arkansas'],
], ],
[
'CA', [
['', 'State/Province'],
['AB', 'Alberta'],
['BC', 'British Columbia'],
['MB', 'Manitoba'],
['NB', 'New Brunswick'],
]]
];
var countryElement = document.getElementById('countryId');
var stateElement = document.getElementById('stateId');
var stateLabelElement = document.getElementById('stateLabel');
if (countryElement && stateElement) {
var listOfState = [
['XX', 'None']
];
var currentCountry = countryElement.options[countryElement.selectedIndex].value;
for (var i = 0; i < countryState.length; i++) {
if (currentCountry == countryState[i][0]) {
listOfState = countryState[i][1];
}
}
if (listOfstate.length < 2)
{
stateElement.style.display = 'none';
stateLabelElement.style.display = 'none';
}
else
{
stateElement.style.display = 'inline';
stateLabelElement.style.display = 'inline';
}
var selectedState;
for (var i = 0; i < stateElement.length; i++) {
if (stateElement.options[i].selected === true) {
selectedState = stateElement.options[i].value;
}
}
stateElement.options.length = 0;
for (var i = 0; i < listOfState.length; i++) {
stateElement.options[i] = new Option(listOfState[i][1], listOfState[i][0]);
if (listOfState[i][0] == selectedState) {
stateElement.options[i].selected = true;
}
}
}
}
</script>
You had a lot of mis-spellings. Check this out: https://jsfiddle.net/jj8we58t/1/
I also set the initial display to none for the stateLabel and stateId elements.
<label id="stateLabel" style="display: none">State:</label>
<select name="<portlet:namespace/>State" style="display: none" id="stateId">
Your code was close, but due to some inconsistencies in variable names, it failed to function. For instance, your onchange event is bound to countryChange, but your function is named CountryChange. It's a good idea to drop your script into some sort of validator like jsHint to analyze why your code isn't working as expected.
with a couple tweaks and those inconsistencies ironed out, it appears to be functioning as expected now
HTML:
<select name="<portlet:namespace/>Country" id="countryId" onchange="window.CountryChange()">
<option value="0">Select Country</option>
<option value='US'>United States</option>
<option value='CA'>Canada</option>
</select>
<div id="stateField" style="display:none">
<label id="stateLabel">State:</label>
<select name="<portlet:namespace/>State" id="stateId">
</select>
</div>
JS:
window.CountryChange = function () {
var countryState = [
[
'US', [
['', 'State/Province'],
['AL', 'Alabama'],
['AK', 'Alaska'],
['AZ', 'Arizona'],
['AR', 'Arkansas'],
],
],
[
'CA', [
['', 'State/Province'],
['AB', 'Alberta'],
['BC', 'British Columbia'],
['MB', 'Manitoba'],
['NB', 'New Brunswick'],
]
]
];
var countryElement = document.getElementById('countryId');
var stateElement = document.getElementById('stateId');
var stateLabelElement = document.getElementById('stateLabel');
var stateFieldElement = document.getElementById('stateField');
if (countryElement && stateElement) {
var listOfState = [
['XX', 'None']
];
var currentCountry = countryElement.options[countryElement.selectedIndex].value;
for (var i = 0; i < countryState.length; i++) {
if (currentCountry == countryState[i][0]) {
listOfState = countryState[i][1];
}
}
if (listOfState.length < 2) {
stateFieldElement.style.display = "none";
} else {
stateFieldElement.style.display = "inline-block";
}
var selectedState;
for (var i = 0; i < stateElement.length; i++) {
if (stateElement.options[i].selected === true) {
selectedState = stateElement.options[i].value;
}
}
stateElement.options.length = 0;
for (var i = 0; i < listOfState.length; i++) {
stateElement.options[i] = new Option(listOfState[i][1], listOfState[i][0]);
if (listOfState[i][0] == selectedState) {
stateElement.options[i].selected = true;
}
}
}
}
Related
I basically want to dynamically update the displayed output json fields based on what value I select in a dropdown, without reloading the page. In this case, display the city based on the selected AveragePrice dropdown. By the way, it's plain javascript (Vanilla)
JSON:
[
{
"country":"UK",
"cities":[
{
"city":"Manchester",
"averagePrice":100
},
{
"city":"London",
"averagePrice":300
},
]
},
{
"country":"France",
"cities":[
{
"city":"Toulouse",
"averagePrice":150
},
{
"city":"Nice",
"averagePrice":200
},
]
},
]
HTML:
<div id="city"></div>
<select id="averagePriceDropdown">
<option value="100">100</option>
<option value="150">150</option>
<option value="175">175</option>
<option value="200">200</option>
<option value="300">300</option>
</select>
Javascript:
var valueDropdown = document.getElementById("averagePriceDropdown");
var valueData = valueDropdown.options[valueDropdown.selectedIndex].value;
var getAverage = async function () {
fetch("../data/data.json").then(
res => {
res.json().then(
data => {
for (var x in data) {
if (data[x].cities[x].averagePrice == valueData) {
return document.getElementById("city").innerHTML += data[x].cities[x].city;
} else {
return document.getElementById("city").innerHTML += "Could not find city.";
}
}
}
)
}
)
};
As you can see, I'm defining variable names for different ID fields. In the IF condition, I am updating the city text content (innerHTML) matching the AveragePrice. It works if I change the default dropdown value in the HTML and reload the page, it renders the correct city. But changing the dropdown on the page, it doesn't update the city. I tried adding an onchange eventlistener to the dropdown but with no success.
The issue is that you are not referencing the array elements correctly. Here is how you want to cycle through the data and make the comparison:
function choose(){
var valueDropdown = document.getElementById("averagePriceDropdown");
var valueData = valueDropdown.options[valueDropdown.selectedIndex].value;
var i, j, match;
match = false;
for (i = 0; i< data.length; i++) {
for (j = 0; j < data[i].cities.length; j++){
if (data[i].cities[j].averagePrice == valueData){
match = true;
console.log("Matching cities: " + data[i].cities[j].city);
document.getElementById("city").innerHTML = data[i].cities[j].city
}
}
}
if (match == false) {
console.log("No matching cities for average price = " + valueData);
document.getElementById("city").innerHTML = "No matching cities.";
}
}
data =
[
{
"country":"UK",
"cities":[
{
"city":"Manchester",
"averagePrice":100
},
{
"city":"London",
"averagePrice":300
},
]
},
{
"country":"France",
"cities":[
{
"city":"Toulouse",
"averagePrice":150
},
{
"city":"Nice",
"averagePrice":200
},
]
},
]
<div id="city"></div>
<select id="averagePriceDropdown" onchange="choose()">
<option value="-">-</option>
<option value="100">100</option>
<option value="150">150</option>
<option value="175">175</option>
<option value="200">200</option>
<option value="300">300</option>
</select>
I am trying to implement a cascading drop down using this. I'm not really familiar with Javascript but I think I'm on the right track. It should display the array values [0, 1, 2, 3] as opposed to the values ["Name", "Definition", "Owner"]
var typeObject = {
StoredProcedures: ["Name", "Definition", "Owner"],
Tables: ["Name", "Definition", "Owner", "Schema"],
Views: ["Name", "Definition", "Owner"]
}
window.onload = function() {
var typeSel = document.getElementById("typeSel"),
fieldSel = document.getElementById("fieldSel")
for (var type in typeObject) {
typeSel.options[typeSel.options.length] = new Option(type, type);
}
typeSel.onchange = function() {
fieldSel.length = 1; // remove all options bar first
if (this.selectedIndex < 1) return; // done
for (var field in typeObject[this.value]) {
fieldSel.options[fieldSel.options.length] = new Option(field, field);
}
}
typeSel.onchange();
I made a modification to your script
var typeObject = {
StoredProcedures: ["Name", "Definition", "Owner"],
Tables: ["Name", "Definition", "Owner", "Schema"],
Views: ["Name", "Definition", "Owner"]
}
window.onload = function () {
var typeSel = document.getElementById("typeSel"),
fieldSel = document.getElementById("fieldSel")
for (var type in typeObject) {
typeSel.options[typeSel.options.length] = new Option(type, type);
}
typeSel.onchange = function () {
fieldSel.length = 1; // remove all options bar first
if (this.selectedIndex < 1) return; // done
var ft = typeObject[this.value];
for (var field in typeObject[this.value]) {
fieldSel.options[fieldSel.options.length] = new Option(ft[field], field);
}
}
typeSel.onchange();
}
<select name="optone" id="typeSel" size="1">
<option value="" selected="selected">Select type</option>
</select>
<br/>
<br/>
<select name="opttwo" id="fieldSel" size="1">
<option value="" selected="selected">Select field</option>
</select>
I have a JSON file with the information of watches. I want to build a simple form that allows a user to select a brand of watch, then the second dropdown would be populated with the values within "Model" and the final dropdown would be populated with the values within "Movement".
I've built what I assume to be right only it isn't working and I'm getting no errors?
HTML
<form name="myform" id="myForm">
<select name="optone" id="brands" size="1">
<option value="" selected="selected">Select a brand</option>
</select>
<br>
<br>
<select name="opttwo" id="model" size="1">
<option value="" selected="selected">Please select model</option>
</select>
<br>
<br>
<select name="optthree" id="movement" size="1">
<option value="" selected="selected">Please select a movement</option>
</select>
</form>
HTML
var watches = {
"Rolex": {
"Model": [
"Submariner",
"Yachtmaster",
"Oyster",
"Datejust"
],
"Movement": [
{
"label": "OysterDate",
"Id": "6694"
},
{
"label": "Hulk",
"Id": "3920"
},
{
"label": "DeepSea",
"Id": "2342"
}
]
},
"Omega": {
"Model": [
"Seamaster",
"Speedmaster",
"MoonWatch"
],
"Movement": [
]
}
}
window.onload = function () {
var brands = document.getElementById("brands"),
model = document.getElementById("model"),
movement = document.getElementById("movement");
for (var brand in watches) {
brands.options[brands.options.length] = new Option(brands, brands);
}
brands.onchange = function () {
model.length = 1; // remove all options bar first
testCase.length = 1; // remove all options bar first
if (this.selectedIndex < 1) return; // done
for (var model in watches[this.value]) {
model.options[model.options.length] = new Option(model, model);
}
}
brands.onchange(); // reset in case page is reloaded
model.onchange = function () {
movement.length = 1; // remove all options bar first
if (this.selectedIndex < 1) return; // done
var movement = watches[brand.value][this.value];
alert(movement);
for (var i = 0; i < movement.length; i++) {
movement.options[movement.options.length] = new Option(movement, movement);
}
}
}
watches();
https://jsfiddle.net/z3xcyprt/3/
Ok, there were a lot of issues here.
Mainly over writing your variable names, but also incorrect navigation of array values, using the for( x in obj) when you should use forEach(func())
Also note that you JSON does not have a relationship between Model and Movement I noted this in the script, but you will likely want to look at that.
var watches = {
"Rolex": {
"Model": [
"Submariner",
"Yachtmaster",
"Oyster",
"Datejust"
],
"Movement": [
{
"label": "OysterDate",
"Id": "6694"
},
{
"label": "Hulk",
"Id": "3920"
},
{
"label": "DeepSea",
"Id": "2342"
}
]
},
"Omega": {
"Model": [
"Seamaster",
"Speedmaster",
"MoonWatch"
],
"Movement": [
]
}
}
const createOption = (value, text) => {
let opt = document.createElement('option');
opt.value = value;
opt.text = text;
return opt;
};
window.onload = function () {
var brands = document.getElementById("brands"),
model = document.getElementById("model"),
movement = document.getElementById("movement");
for (var brand in watches) {
brands.options.add(createOption(brand, brand));
}
brands.onchange = function () {
model.length = 1; // remove all options bar first
if (brands.selectedIndex < 1) return; // done
// This is an array of string.
watches[brands.value].Model.forEach(m => {
model.add( createOption(m, m));
});
}
// There is NO link in the JSON between model and movement ?
model.onchange = function () {
movement.length = 1; // remove all options bar first
if (this.selectedIndex < 1) return; // done
watches[brands.value].Movement.forEach(m => {
movement.options.add(createOption(m.Id, m.label));
});
}
}
// This does nothing.
//watches();
<form name="myform" id="myForm">
<select name="optone" id="brands">
<option value="" selected="selected">Select a brand</option>
</select>
<br>
<br>
<select name="opttwo" id="model">
<option value="" selected="selected">Please select model</option>
</select>
<br>
<br>
<select name="optthree" id="movement">
<option value="" selected="selected">Please select a movement</option>
</select>
</form>
Try with this.
On window.onload function you are declaring the brands, model but you are overriding it in the loops.
Also read about the differences between for ... of and for ... in
window.onload = function () {
var brands = document.getElementById("brands"),
model = document.getElementById("model"),
movement = document.getElementById("movement");
for (var brand in watches) {
brands.options[brands.options.length] = new Option(brand);
}
brands.onchange = function () {
if (this.selectedIndex < 1) return; // done
for (var modelValue of watches[this.value].Model) {
model.options[model.options.length] = new Option(modelValue);
}
}
brands.onchange(); // reset in case page is reloaded
model.onchange = function () {
if (this.selectedIndex < 1) return; // done
var movementValue = watches[brands.value].Movement;
for (var i = 0; i < movementValue.length; i++) {
movement.options[movement.options.length] = new Option( movementValue[i].label, movementValue[i].Id);
}
}
}
watches();
I have an ecommerce site that has products with multiple attributes (e.g. size, colour, etc,.)
On each product page there is a dropdown for each attribute with a class of 'attribute_price'.
I have also preloaded hidden inputs onto the page from my database with the pricing for each product with a class of 'hidden_attribute_value'.
So not every combination of size and colour is an option. For example, we might have 'small_red' or 'medium_red' but no 'large_red'
So if they select 'large' from the size dropdown menu 'red' should not be an option for the colour.
What I have so far is:
$("select.attribute_price").on("change", function(){
var id = event.target.id;
// determine which dropdown was changed (size or colour)
var attribute_value = document.getElementById(id).value+'_';
// get the value of the dropdown that they selected
var other_attribute_ids = []
var i;
var other_attributes = document.getElementsByClassName("attribute_price");
for(i=0; i<other_attributes.length; i++){
if(other_attributes[i].id != id){
var other_attribute_id = document.getElementById(other_attributes[i].id).id;
other_attribute_ids.push(other_attribute_id);
}
}
// create an array of all of the other dropdown ids excluding the one they changed
var all_attribute_ids = []
var i;
var all_attributes = document.getElementsByClassName("hidden_attribute_value");
for(i=0; i<all_attributes.length; i++){
all_attribute_ids.push(all_attributes[i].id);
}
// create an array of all of the possible values that it can be
});
So I have a variable 'attribute_value' which would be something like 'red_' or 'blue_'.
I have an array called 'all_attribute_values' which has the ids of hidden inputs for all possible combinations. These would have values like 'small_red_' or 'small_blue'.
And I have an array called 'other_attribute_ids' which has the id of the other dropdown menus that haven't been selected.
So if an item in 'all_attribute_values' does not contain 'attribute_value' remove that option from 'other_attribute_ids'.
I have created a sample html based on your usecase. Solution is likewise, but you should get inspiration for solving yours.
I have considered independent attributes, so the solution will scale to new attributes with different values. I have also considered that server response is not editable.
I have a quick link in jsfiddle to checkout the solution
https://jsfiddle.net/nfLx6aok/1/
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<select id="size" class="attribute_price">
<option value="small">Small</option>
<option value="large">Large</option>
</select>
<select id="color" class="attribute_price">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="black">Black</option>
</select>
<select id="pattern" class="attribute_price">
<option value="solids">Solids</option>
<option value="checked">Checked</option>
<option value="dots">Dots</option>
</select>
<input type="hidden" id="small_red_solids" class="hidden_attribute_value">
<input type="hidden" id="small_black_dots" class="hidden_attribute_value">
<input type="hidden" id="large_green_checked" class="hidden_attribute_value">
<script>
// on page load
$( document ).ready(function() {
renderOptions();
});
$("select.attribute_price").on("change", function () {
renderOptions();
});
function renderOptions() {
// create an array of all of the possible values that it can be
// allowed_attribute_values = ['small_red', 'large_blue']
var allowed_attribute_values = [];
var all_attributes = document.getElementsByClassName("hidden_attribute_value");
for (var i = 0; i < all_attributes.length; i++) {
allowed_attribute_values.push(all_attributes[i].id);
}
function getAllPossibleValues(current_level, all_attributes) {
var depth_index = all_attributes.length;
var selected_combination = '';
for (var i = 0; i < depth_index; i++) {
if (i <= current_level) {
selected_combination += all_attributes[i].value;
if (i != all_attributes.length - 1) {
selected_combination += '_';
}
}
}
// hide all lower options
for (var i = current_level + 1; i < depth_index; i++) {
var selectedIdOptions = all_attributes[i].options;
all_attributes[i].value = null
for (var j = 0; j < selectedIdOptions.length; j++) {
// hide all lower options
selectedIdOptions[j].hidden = true;
var el = allowed_attribute_values.find(a => a.includes(selected_combination + selectedIdOptions[j].value));
if (el) {
selectedIdOptions[j].hidden = false;
}
}
}
}
if (event) {
var id = event.target.id;
} else {
var id = document.getElementsByClassName("attribute_price")[0].id;
}
var other_attributes = document.getElementsByClassName("attribute_price");
for (var i = 0; i < other_attributes.length; i++) {
if (other_attributes[i].id == id) {
allPossibleValues = getAllPossibleValues(i, other_attributes);
// we dont want to go deeper as of now
break;
}
}
}
</script>
this would work with any number of dropdown.
you can generate random attributes to test.
$(document).ready(function () {
/* generates random attributes */
var div_attributes = $('#div_attributes');
var select_colors = $('#select_colors');
var select_sizes = $('#select_sizes');
var select_attr0 = $('#select_attr0');
var select_attr1 = $('#select_attr1');
$('#btnGenerate').on('click', function () {
var result = "";
//
var index = getRandomArbitrary(1, select_sizes.find('option').get().length);
var random_attribute = select_sizes.find('option').eq(index).attr('value');
result += random_attribute;
//
index = getRandomArbitrary(1, select_colors.find('option').get().length);
random_attribute = select_colors.find('option').eq(index).attr('value');
result += '_' + random_attribute;
//
index = getRandomArbitrary(1, select_attr0.find('option').get().length);
random_attribute = select_attr0.find('option').eq(index).attr('value');
result += '_' + random_attribute;
//
index = getRandomArbitrary(1, select_attr1.find('option').get().length);
random_attribute = select_attr1.find('option').eq(index).attr('value');
result += '_' + random_attribute;
$('<div>' + result + '</div>').appendTo(div_attributes);
div_attributes.find('div').each(function () {
var item = $(this);
attributes.push(item.text());
});
SetFirstSelect();
});
var attributes = [];
//sets first select
SetFirstSelect();
function SetFirstSelect() {
$.each(attributes, function (i, val) {
var attribute = val.split('_')[0];
$('.attribute_price').eq(0).find('option[value="' + attribute + '"]').show();
});
}
//control attributes array
var selected_val = [];
$('.attribute_price').on('change', function () {
var item = $(this);
var index = item.index('.attribute_price');
selected_val[index] = item.val();
var select = $('.attribute_price').eq(index + 1);
var selected_attribute = item.val();
for (var i = index + 1; i < $('.attribute_price').get().length; i++) {
$('.attribute_price').eq(i).find('option').hide();
$('.attribute_price').eq(i).prop('selectedIndex', 0)
}
var selected_val_str = selected_val[0];
for (var i = 1; i <= index; i++) {
selected_val_str += '_' + selected_val[i];
}
$.each(attributes, function (j, val) {
if (val.indexOf(selected_val_str) >= 0) {
var attribute1 = val.split('_')[index + 1];
select.find('option[value="' + attribute1 + '"]').show();
}
});
});
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
});
.attribute_price option {
display: none;
}
.container {
margin:30px;
}
.row > div {
padding:10px;
}
.btn {
margin-top:20px;
}
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<div class="container">
<div class="row">
<div style="width:50%; float:left">
<input type="button" class="btn btn-primary" id="btnGenerate" value="generate random attributes" />
<div id="div_attributes"></div>
</div>
<div style="width:50%; float:left">
<div class="form-group">
<label>Sizes</label>
<select class="form-control attribute_price" id="select_sizes">
<option value="">select size</option>
<option value="small">small</option>
<option value="large">large</option>
<option value="medium">medium</option>
</select>
</div>
<div class="form-group">
<label>color</label>
<select id="select_colors" class="form-control attribute_price">
<option value="">select color</option>
<option value="black">black</option>
<option value="yellow">yellow</option>
<option value="red">red</option>
</select>
</div>
<div class="form-group">
<label>attrType0</label>
<select id="select_attr0" class="form-control attribute_price">
<option value="">select attr0</option>
<option value="attr00">attr00</option>
<option value="attr01">attr01</option>
<option value="attr02">attr02</option>
</select>
</div>
<div class="form-group">
<label>attrType1</label>
<select id="select_attr1" class="form-control attribute_price">
<option value="">select attr1</option>
<option value="attr10">attr10</option>
<option value="attr11">attr11</option>
<option value="attr12">attr12</option>
</select>
</div>
</div>
</div>
</div>
I don't know if I have understood exactly what you are trying to explain or not but here's what I understood
you have a website with suppose dropdowns for say clothes having attributes size, price, color, brand and you have an array of objects containing all of these attributes for each object.
I will be explaining this in reactjs since i am more familiar with it than php
so for each dropdown you can have an onchange handler which invokes a function where you check the values of the other dropdowns. If You select size M then enable and populate the dropdown list after filtering clothes with size M. when that is done invoke a similar function for checking the other attributes.
at this time all of your dropdowns will be active, now if the user makes any changes to the first dropdown i.e. size you can either reset the other dropdowns to be reselected or just pass the new list depending on how you are handling
Here is a similar thing i had done for setting date
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July','August', 'September', 'October', 'November', 'December']
const Month30 = ['4', '6', '9', '11']
const Month31 = ['1', '3', '5', '7', '8', '10', '12']
class Dropdown extends React.Component {
constructor(props) {
super(props)
this.state = {
birthDay: '',
birthMonth: '',
birthYear: ''
}
}
componentDidMount() {
}
getMonthTotalDays = (birthMonth, birthYear) => {
if (birthMonth === '02') {
if (birthYear !== '' && birthYear % 4 === 0) {
return 29
} else {
return 28
}
} else if (Month30.includes(birthMonth)) {
return 30
} else {
return 31
}
}
handleChange = e => {
this.setState({
[e.target.name]: e.target.value
}, () => {
const { birthMonth, birthYear, birthDay } = this.state
const days = this.getMonthTotalDays(birthMonth, birthYear)
if (birthDay > days) {
this.setState({ birthDay: '' })
}
})
}
renderMonths = () => {
return months.map((month, i) => {
if(i < 9){
return (<option key={`${month}-${i}`} value={'0' + (i + 1)}>{month}</option>)
}
else
return (<option key={`${month}-${i}`} value={i + 1}>{month}</option>)
})
}
renderDay = () => {
const { birthMonth, birthDay, birthYear } = this.state
const daysOptions = []
let days = this.getMonthTotalDays(birthMonth, birthYear)
for (let day=1; day<=days; day++) {
daysOptions.push(<option key={`'date-'${day}`} value={day}> { day } </option>)
}
return daysOptions
}
renderYears = () => {
const toYear = (new Date()).getFullYear() - 16
const yearOptions = []
for (let year = 1960; year <= toYear; year++) {
yearOptions.push(<option key={`year-${year}`} value={year}> { year } </option>)
}
return yearOptions
}
render() {
const { birthDay, birthMonth, birthYear } = this.state
return (
<div>
<label>Month</label>
<select
name="birthMonth"
value={ birthMonth }
onChange={this.handleChange}
>
<option disabled selected value=''>Month</option>
{ this.renderMonths() }
</select>
<label>Day</label>
<select
name='birthDay'
value={ birthDay }
onChange={this.handleChange}
>
<option disabled selected value=''>Day</option>
{ this.renderDay() }
</select>
<label>Year</label>
<select
name='birthYear'
value={ birthYear }
onChange={this.handleChange}
>
<option disabled selected value=''>Year</option>
{ this.renderYears() }
</select>
</div>
)
}
}
ReactDOM.render(
<Dropdown />,
document.getElementById('drop')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="drop"></div>
Here is a solution that takes a skus array as input and create a dropdown for each attribute. When any dropdown value changes, the options in all other dropdowns are updated to show only options consistent with picked options.
https://codepen.io/rockysims/pen/PyJbbv
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script type="text/javascript">
skus = [{
id: 1,
attributes: {
color: "red",
size: "small",
shape: "circle"
}
}, {
id: 2,
attributes: {
color: "red",
size: "medium",
shape: "square"
}
}, {
id: 3,
attributes: {
color: "yellow",
size: "small",
shape: "circle"
}
}, {
id: 4,
attributes: {
color: "yellow",
size: "medium",
shape: "square"
}
}, {
id: 5,
attributes: {
color: "yellow",
size: "large",
shape: "square"
}
}, {
id: 6,
attributes: {
color: "green",
size: "medium",
shape: "square"
}
}, {
id: 7,
attributes: {
color: "green",
size: "large",
shape: "square"
}
}];
$(function() {
const allOptionsByAttrName = buildAllOptionsByAttrName();
//create dropdowns
for (let attrName in allOptionsByAttrName) {
const dropdownId = attrName + "Dropdown";
const options = allOptionsByAttrName[attrName];
let html = "";
html += attrName + ": ";
html += buildDropdownHtml(dropdownId, options);
html += "<br/>";
$("#dropdowns").append(html);
}
//on dropdown changes, update options of all dropdowns
for (let changedAttrName in allOptionsByAttrName) {
$("#" + changedAttrName + "Dropdown").on('change', function() {
//build pickedOptionByAttrName
const pickedOptionByAttrName = {};
for (let attrName in allOptionsByAttrName) {
const dropdown = $("#" + attrName + "Dropdown");
pickedOptionByAttrName[attrName] = dropdown.val();
}
refreshAvailableOptions(pickedOptionByAttrName);
});
}
});
function buildAllOptionsByAttrName() {
const allOptionsByAttrName = {};
for (let sku of skus) {
for (let attrName in sku.attributes) {
allOptionsByAttrName[attrName] = allOptionsByAttrName[attrName] || [];
if (allOptionsByAttrName[attrName].indexOf(sku.attributes[attrName]) == -1) {
allOptionsByAttrName[attrName].push(sku.attributes[attrName]);
}
}
}
return allOptionsByAttrName;
}
function buildDropdownHtml(dropdownId, options) {
let html = "";
html += "<select id='" + dropdownId + "'>";
html += "<option value=''>";
html += "";
html += "</option>";
for (let option of options) {
html += "<option value='" + option + "'>";
html += option;
html += "</option>";
}
html += "</select>";
return html;
}
function refreshAvailableOptions(pickedOptionByAttrName) {
for (let attrName in pickedOptionByAttrName) {
//build availableOptions
const dropdown = $("#" + attrName + "Dropdown");
const options = $("#" + attrName + "Dropdown option");
const availableOptions = buildAvailableOptions(pickedOptionByAttrName, attrName);
availableOptions.push(""); //nothing picked option
//show available options and hide others
options.each(function() {
const option = $(this);
const optionIsAvailable = availableOptions.indexOf(option.val()) != -1;
if (optionIsAvailable) {
option.show();
} else {
option.hide();
}
});
}
}
function buildAvailableOptions(pickedOptionByAttrName, attrNameToBuildFor) {
//build availableSkus
const availableSkus = skus.filter(function(sku) {
let available = true;
for (let attrName in pickedOptionByAttrName) {
if (attrName != attrNameToBuildFor) {
const pickedOption = pickedOptionByAttrName[attrName];
if (pickedOption) {
available = available && sku.attributes[attrName] == pickedOption;
}
}
}
return available;
});
//build availableOptions
const availableOptions = [];
for (let sku of availableSkus) {
if (availableOptions.indexOf(sku.attributes[attrNameToBuildFor]) == -1) {
availableOptions.push(sku.attributes[attrNameToBuildFor]);
}
}
return availableOptions;
}
</script>
<div id="dropdowns">
</div>
If you prefer not to dynamically create the dropdowns, comment out the for loop under //create dropdowns and replace <div id="dropdowns"></div> with the following:
<div id="dropdowns">
color:
<select id="colorDropdown">
<option value=""></option>
<option value="red">red</option>
<option value="yellow">yellow</option>
<option value="green">green</option>
</select><br/>
size:
<select id="sizeDropdown">
<option value=""></option>
<option value="small">small</option>
<option value="medium">medium</option>
<option value="large">large</option>
</select><br/>
shape:
<select id="shapeDropdown">
<option value=""></option>
<option value="circle">circle</option>
<option value="square">square</option>
</select><br>
</div>
If you can identify in PHP which options for other categories are available for certain drop-down category-value selection. You can incrementally flag each option as excluded for each selected value to keep it disabled:
JS:
$(document).ready(function () {
$(".dropdown").change(function(){
var val = $(this).val();
var id = $(this).attr('id');
$.get('get_options.php', {category: id, value:val}, function(data) {
$(".dropdown:not(#"+id+")").each(function() {
var cat = $(this).attr('id');
$(this).find('option').each(function() {
var cat_val = $(this).val();
var options = data[cat];
var exluded = $(this).attr('exlude');
if ($.inArray(cat_val, options) !== -1) {
$(this).attr('exlude', exluded-1);
if(exluded == 1) {
$(this).prop('disabled', false);
}
} else {
$(this).attr('exlude', exluded+1);
$(this).prop('disabled', true);
}
});
});
}, 'json');
});
});
HTML:
<div id="dropdowns">
color:
<select id="color" class="dropdown">
<option value=""></option>
<option value="red">red</option>
<option value="yellow">yellow</option>
<option value="green">green</option>
</select><br/>
size:
<select id="size" class="dropdown">
<option value=""></option>
<option value="small">small</option>
<option value="medium">medium</option>
<option value="large">large</option>
</select><br/>
shape:
<select id="shape" class="dropdown">
<option value=""></option>
<option value="circle">circle</option>
<option value="square">square</option>
<option value="triangle">triangle</option>
</select><br>
**SAMPLE DATA: ** example if user selects color first, return all available options for other drop-down categories.
{"size": ["small","large"],"shape":["circle"]}
or in php:
$data = array(
'size' => array(
'small', 'large'
),
'shape' => array(
'circle'
),
);
echo json_encode($data);
Im stack on creating multiple select options
I have an Object with multi objects inside and want create select options in condition of the previous select option , i provide js fiddle for better understanding .
my objectif is
first select category ----(then)---> select sex -----(then)---> select kind---(then)-->then select size
by this order from that Object.
i could do the select sex and it works but not kind and size.
this is my html
<form name="myform">
<div>
<select name="category_group" id="category_group" >
<option value="0">choose category</option>
<option value='401' > clothes </option>
<option value='403' > shoes </option>
</select>
</div>
<br>
<div>
<select id="clothing_sex" name="clothing_sex" onChange="showclothesKind(this.value,this.form.clothing_kind)">
<option value="0">choose Type»</option>
</select>
<select id="clothing_kind" name="clothing_kind">
<option value="0">choose clothes</option>
</select>
<select id="clothing_size" name="clothing_size">
<option value="0">choose size</option>
</select>
</div>
</form>
and js in the fiddle.
much appreciate your help.
This was kind of fun to play around with. Thanks for posting. I used the following:
var optionTemplate = "<option class='newOption'>sampleText</option>";
$(document).ready(function() {
var removeFromNextSelects = function(firstSelector) {
var selNum = sels.indexOf(firstSelector);
for (var i = selNum; i < sels.length; i++)
{
$(sels[i]).find('.option').remove();
}
};
var populateNextSelect = function(neededObject, targetSelector) {
removeFromNextSelects(targetSelector);
for (var key in neededObject)
{
var name;
neededObject[key].name ? name = neededObject[key].name : name = neededObject[key];
$(targetSelector).append(optionTemplate);
$('.newOption').val(key).html(name).removeClass('newOption').addClass('option');
}
};
var obj1 = {}, obj2 = {}, obj3 = {};
var sels = ["#clothing_sex", "#clothing_kind", "#clothing_size"];
$('#category_group').change(function() {
if ($(this).val() == 0)
{
removeFromNextSelects(sels[0]);
return;
}
obj1 = {};
var selection = $(this).val();
obj1 = clothes[selection];
populateNextSelect(obj1, sels[0]);
});
$('#clothing_sex').change(function() {
if ($(this).val() == 0)
{
removeFromNextSelects(sels[1]);
return;
}
obj2 = {};
var selection = $(this).val();
obj2 = obj1[selection].types;
populateNextSelect(obj2, sels[1]);
});
$('#clothing_kind').change(function() {
if ($(this).val() == 0)
{
removeFromNextSelects(sels[2]);
return;
}
obj3 = {};
var selection = $(this).val();
var arr = obj2[selection].sizes;
for (var i = 0; i < arr.length; i++)
{
obj3[Object.keys(arr[i])[0]] = arr[i][Object.keys(arr[i])[0]];
}
populateNextSelect(obj3, sels[2]);
});
});
Here's the fiddle