I looked this over a bit and at first thought it should be similar to other postings however you do not sort by either the ID or the Name (text) but by some other value. In order to facilitate that, I created an object that holds all the countries and cities and then puts them in. I then sort using a sortOrder from that that gets pushed into the options list as data-sort
and a function to do the sort.
I see your currentCity
but that would likely change on a country change? So I put a "default" for each country by putting an isDefault:true
on a city.
I also pushed the countries in from the list as well, with a default there.
This may be overkill for your situation but take what you like from this.
Create a namespace
var myApp = myApp || {};// create a namespace to use.
Add a countries object:
myApp.countries = [{
"name": "United Kingdom",
isDefault: true,
id: 1,
"cities": [{
id: 1,
name: "Bedfordshire",
"sortOrder": 1,
"isCapital": false
}, {
id: 2,
name: "Berkshire",
"sortOrder": 2,
"isCapital": false
}, {
id: 3,
name: "Birmingham",
"sortOrder": 3,
"isCapital": false
}, {
id: 4,
name: "Brighton",
"sortOrder": 4,
"isCapital": false,
isDefault:true
}, {
id: 5,
name: "Buckinghamshire",
"sortOrder": 6,
"isCapital": false
}, {
id: 6,
name: "Appleton",
"sortOrder": 5,
"isCapital": false
}, {
id: 37,
name: "London",
"sortOrder": 0,
"isCapital": true
}]
}, {
"name": "Hackem",
id: 2,
"cities": [{
id: 1,
name: "Somecity",
"sortOrder": 1,
"isCapital": false
}, {
id: 2,
name: "Waterton",
"sortOrder": 2,
"isCapital": false
}, {
id: 3,
name: "Acre City",
"sortOrder": 3,
"isCapital": false
}, {
id: 4,
name: "Jackson",
"sortOrder": 4,
"isCapital": false
}, {
id: 5,
name: "Tolkenshire",
"sortOrder": 6,
"isCapital": false
}, {
id: 6,
name: "Capital City",
"sortOrder": 0,
"isCapital": true
}, {
id: 37,
name: "Paris",
"sortOrder": 4,
"isCapital": false
}]
}, {
"name": "NewCountry",
id: 3,
"cities": [{
id: 1,
name: "Skycity",
"sortOrder": 1,
"isCapital": false
}, {
id: 2,
name: "DirtCity",
"sortOrder": 2,
"isCapital": false
}, {
id: 3,
name: "Airville",
"sortOrder": 3,
"isCapital": false
}, {
id: 6,
name: "Cape Town",
"sortOrder": 0,
"isCapital": true
}, {
id: 37,
name: "Walla Walla",
"sortOrder": 4,
"isCapital": false
}]
}];
Add some functions to namespace to use:
myApp.arrayObj = myApp.arrayObj || {
lookup: function(myArray, searchTerm, property, firstOnly) {
var found = [];
for (var i = 0; i < myArray.length; i++) {
if (myArray[i][property] === searchTerm) {
found.push(myArray[i]);
if (firstOnly) break; //if only the first
}
}
return found;
},
updateCityOptions: function(countries) {
var $cityAll = $("#ListingCity");
// lookup by text
var $countryText = $("#ListingCountry option:selected").text();
var ac = this.lookup(countries, $countryText, "name", true)[0].cities;
// lookup by id (alternate approach)
// var $countryId = $("#ListingCountry option:selected").val();
// var ac = this.lookup(countries, $countryId , "id", true)[0].cities;
if (ac) {
$('#ListingCity option:gt(0)').remove();
var opt = '<option></option>';
var newOptions = "";
$.each(ac, function(k2, v2) {
// var sel = currentCity == v2.name ? ' selected="selected" ' : "";
var sel = v2.isDefault ? ' selected="selected" ' : "";
opt = '<option data-sort="' + v2.sortOrder + '"' + sel + ' value="' + v2.id + '">' + v2.name + '</option>';
newOptions += opt;
});
$cityAll.append(newOptions); //hit the DOM just once
$cityAll.sortOptions(); // sort what we put in
$(".city").fadeIn(300);
} else {
$cityAll.find('option:gt(0)').remove();
$(".city").fadeOut(300);
}
$cityAll.trigger('change');// because it changed
},
setCountries: function(nation) {
var $countries = $("#ListingCountry");
$countries.find('option:gt(0)').remove();
var opt = '';
var newOptions = "";
$.each(nation, function(k2, v2) {
var sel = v2.isDefault ? ' selected="selected" ' : "";
opt = '<option data-sort="' + v2.sortOrder + '"' + sel + ' value="' + v2.id + '">' + v2.name + '</option>';
newOptions += opt;
});
$countries.append(newOptions); //hit the DOM just once
}
};
Create the key sort function:
// sort the select
$.fn.sortOptions = function() {
$(this).each(function() {
var op = $(this).children("option");
op.sort(function(a, b) {
return $(a).data('sort') > $(b).data('sort') ? 1 : -1;
})
return $(this).empty().append(op);
});
}
Startup code:
myApp.arrayObj.setCountries(myApp.countries);
// could be done is way but we trigger the country change which does this
// myApp.arrayObj.updateCityOptions(myApp.countries);
Handle the country change event:
$('#ListingCountry').on('change', function() {
myApp.arrayObj.updateCityOptions(myApp.countries);
}).trigger('change');
Edit: Note you could remove all the "isCapital": false
if you like only keeping the "isCapital": true
on one and it would work the same way.
Sample to play with here: https://jsfiddle.net/MarkSchultheiss/okk22ovq/2/
EDIT: Bonus; alternate sort options
// sort the select
$.fn.sortOptionsByText = function() {
$(this).each(function() {
var op = $(this).children("option");
op.sort(function(a, b) {
return a.text > b.text ? 1 : -1;
})
return $(this).empty().append(op);
});
}
// sort the select
$.fn.sortOptionsByValue = function() {
$(this).each(function() {
var op = $(this).children("option");
op.sort(function(a, b) {
return a.value > b.value ? 1 : -1;
})
return $(this).empty().append(op);
});
}
// sort the select **IF** we had a "mostused" data-mostused value
// sort the select
$.fn.sortOptions = function() {
$(this).each(function() {
var op = $(this).children("option");
op.sort(function(a, b) {
return $(a).data('mostused') > $(b).data('mostused') ? 1 : -1;
})
return $(this).empty().append(op);
});
}