Reputation: 1591
I have three drop downs. For Country, Region/State and City as follows:
Following is the markup:
<div class="form-group">
<label for="country">Country</label>
<select class="form-control" id="country">
</select>
</div>
<div class="form-group">
<label for="region">Region</label>
<select class="form-control" id="region">
</select>
</div>
<div class="form-group">
<label for="city">City</label>
<select class="form-control" id="city">
</select>
</div>
On selecting a value in any of the three drop down the available options inside the other two drop downs needs to be filtered depending upon the selected value in all the three dropdowns at any point of time. Please note: I am using jQuery.
So far i have done this for filtering on the basis of the only the one changed dropdown value instead of considering all and also it filters value when user goes Country to--> Region to--> City. How to consider the values in other dropdown as well as filter the values here if user goes bottom to up say City --> Region --> Country as well ?
$("#country").on('change', function(){
var selectedCntry = $("#country option:selected").val();
console.log(selectedCntry);
var ddRegions = [];
var ddCities = [];
$.each(ddVals, function(i,val){
if( val.country == selectedCntry){
ddRegions.push(val.region);
ddCities.push(val.city);
}
});
if(ddRegions.length > 0){
var regions = "<option value='none'> Select Region </option>";
$.each(ddRegions, function(i,val){
regions += "<option value="+"'"+val+"'"+">"+val+"</option>";
});
$("#region").html(regions);
}
if(ddCities.length > 0){
var cities = "<option value='none'> Select City </option>";
$.each(ddCities, function(i,val){
cities += "<option value="+"'"+val+"'"+">"+val+"</option>";
});
$("#city").html(cities);
}
});
$("#region").on("change",function(){
var selectedReg = $("#region option:selected").val();
console.log(selectedReg);
var ddRegionBasedCity = [];
$.each(ddVals, function(i,val){
if( val.region == selectedReg){
ddRegionBasedCity.push(val.city);
}
});
if(ddRegionBasedCity.length > 0){
var cities = "<option value='none'> Select City </option>";
$.each(ddRegionBasedCity, function(i,val){
cities += "<option value="+"'"+val+"'"+">"+val+"</option>";
});
$("#city").html(cities);
}
});
Here "ddVals" is a variable having an array with json object from which i am filtering the values to be as options in dropdowns. The array looks like as follows:
[{
"city": "Houston",
"country": "United States",
"region": "Texas"
}, {
"city": "Oegstgeest",
"country": "Netherlands ",
"region": "South Holland"
}, {
"city": "Houston",
"country": "United States",
"region": "Texas"
}, {
"city": "Wellington",
"country": "New Zealand ",
"region": "-"
}, {
"city": "London",
"country": "United Kingdom",
"region": "Great Britain"
}, {
"city": "Federal Way",
"country": "United States",
"region": "Washington"
}, {
"city": "Armonk",
"country": "United States",
"region": "New York"
}, {
"city": "San Ramon",
"country": "United States",
"region": "California"
}, {
"city": "New York City",
"country": "United States",
"region": "New York"
}, {
"city": "Roseland",
"country": "United States",
"region": "New Jersey"
}]
Upvotes: 0
Views: 3193
Reputation: 1591
I finally used lodash to filter the json data. It made my task very easy and straight forward. I just created a function as follows and called it on change of every dropdown. The function below is taking the selected value from each dropdown and is passing it to _filter method provide by lodash. It now gives back the filter, limited json data which matches the passed value. Later on i am iterating on that to generate the markup and injecting it to the document. At the same time, i am keeping the selectedValue unchanged on every dropdown by setting it back.
function filterDropDown(ddVals){
var selCity = $('#city').find(":selected").val();
var selRegion = $('#region').find(":selected").val();
var selCountry = $('#country').find(":selected").val();
var selData = {};
if( selCity !== "none"){
selData['city'] = selCity;
}
if(selRegion !== "none"){
selData['region'] = selRegion;
}
if(selCountry !== "none"){
selData['country'] = selCountry;
}
var filteredObj = _.filter(ddVals, selData);
var ddCountries = [];
var ddRegions = [];
var ddCities = [];
$.each(filteredObj, function(i,val){
if(ddCountries.indexOf(val.country) == -1){
ddCountries.push(val.country);
}
if(ddRegions.indexOf(val.region) == -1){
ddRegions.push(val.region);
}
if(ddCities.indexOf(val.city) == -1){
ddCities.push(val.city);
}
});
if(ddCountries.length > 0){
var countries = "<option value='none'> Select Country </option>";
$.each(ddCountries, function(i,val){
countries += "<option value="+"'"+val+"'"+">"+val+"</option>";
});
$("#country").html(countries);
$("#country option[value='"+selCountry+"']").prop('selected', true);
}
if(ddRegions.length > 0){
var regions = "<option value='none'> Select Region </option>";
$.each(ddRegions, function(i,val){
regions += "<option value="+"'"+val+"'"+">"+val+"</option>";
});
$("#region").html(regions);
$("#region option[value='"+selRegion+"']").prop('selected', true);
}
if(ddCities.length > 0){
var cities = "<option value='none'> Select City </option>";
$.each(ddCities, function(i,val){
cities += "<option value="+"'"+val+"'"+">"+val+"</option>";
});
$("#city").html(cities);
$("#city option[value='"+selCity+"']").prop('selected', true);
}
}
Upvotes: 0
Reputation: 5774
I would go for a sep. filter function:
// data is your location data (used in the filter method)
// might be better to remove this from global namespace.
var data = [{
"city": "Houston",
"country": "United States",
"region": "Texas"
}];
/* @param filterBy the key for your ojects (city, country)
* @param filterVal the value to check for
*/
function filterData( filterBy, filterVal) {
return data.map(function(row) {return row}).filter(function(value) {
if(value[filterBy] == filterVal) {
return true;
}
return false;
});
}
This function you can use to get a filtered array for all your three fields depending on each selection. The following jquery code is untested, more pseudo-code to demonstrate how to use the filter:
$(".form-control select").on('change', function() {
// using the field id as object-key.
// second, call filterdata with the key and the current val.
var identifier = this.id,
fData = filterData( identifier, $(this).val());
// now all you need to do is to loop over all your fields
// and update all select fields by using the filtered Data..
$(".form-control select").each(function() {
var cid = this.id, c = '',
emptyText = $(this).find("option[value='']").text();
// get the 'Please Select' for each field
c += '<option value="">' + emptyText + '</option>';
// loop over all available data elements of the filtered data
// if the object-key is the same as current id,
// add a selection...
for( var i=0, l = fData.length; i < l; i++) {
foreach( prop in fData[i]) {
if (prop == cid) {
c +="<option value="+"'"+fData[i][cid]+"'"+">"+
fData[i][cid]+"</option>";
}
}
}
$(this).html(c);
});
});
As I said, the jQuery code is untested, but you can easily verify the filter method, by calling it directly, for example:
console.log(filterData( 'city', 'Roseland'));
console.log(filterData( 'region', 'New Jersey'));
console.log(filterData( 'country', 'United States'));
In addition to this, due to the comment below, here is another filter method which can handle all field values at once. All you need to do is to collect the current values of all fields (and their keys), store it in an object and the filter method will return the matching data. conditionAll
is a boolean flag to decide if all filters must match (true) or just one (false).
function multiFilterData( filters, conditionAll ) {
return data.map(function(row) {return row}).filter(function(value) {
for(var key in filters) {
if( conditionAll && value[key] != filters[key]) {
return false;
} else if( !conditionAll && value[key] == filters[key]) {
return true;
}
}
return (conditionAll) ? true : false;
});
}
// all conditions must fit (this won't work in many cases)
console.log(multiFilterData( {city:'Roseland',region:'-', country:'-'}, true ));
// one condition must fit
console.log(multiFilterData( {city:'Roseland',region:'-', country:'-'}, false ));
Upvotes: 1