I'm looking to take my JS skills to the next level - please be harsh...
define(["serviceApp", 'appConfig', "services/vehicleService"], function (serviceApp, appConfig) {
serviceApp.directive('vehicleSelector', [
'$compile', 'vehicleService', function ($compile, vehicleService) {
return {
restrict: 'EA',
transclude: true,
link: function(scope, element) {
function selectorItems(model, name, service, method, prev) {
var self = this;
this.items = [];
this.model = model;
this.name = name;
this.service = service;
this.method = method;
this.isLoading = false;
this.prev = prev;
this.next = null;
this.isVisible = true;
this.get = function() {
return self.model[self.name];
};
this.set = function(value) {
self.model[self.name] = value;
};
this.setItems = function(items) {
self.items = items;
};
this.args = function() {
var curr = this.prev,
args = [];
while (curr != null) {
args.push(curr.get());
curr = curr.prev;
}
return args.reverse();
};
this.load = function() {
self.isLoading = true;
self.service[self.method].apply(null, self.args())
.then(function (resp) {
self.setItems(resp);
if (resp == null || resp.length == 0) self.hide();
})
.finally(function() {
self.isLoading = false;
});
if (self.next != null && self.next.get()) self.next.load();
};
this.hide = function () {
self.isVisible = false;
if (self.next != null) self.next.hide();
}
this.clear = function() {
if (self.next != null) self.next.clear();
self.setItems([]);
self.set(null);
};
this.onChange = function() {
if (self.next != null) {
self.next.clear();
self.next.load();
}
};
this.isEmpty = function() {
return self.items.length < 1;
};
this.prompt = function () {
return self.isLoading ? "loading" : self.isEmpty() ? "" : "select a " + self.name;
}
this.setNext = function(obj) {
self.next = obj;
if (self.prev != null) self.prev.setNext(self);
};
}
scope.years = new selectorItems(scope.vehicle, "year", vehicleService, "GetYears", null);
scope.makes = new selectorItems(scope.vehicle, "make", vehicleService, "GetMakes", scope.years);
scope.models = new selectorItems(scope.vehicle, "model", vehicleService, "GetModels", scope.makes);
scope.trims = new selectorItems(scope.vehicle, "trim", vehicleService, "GetTrims", scope.models);
scope.trims.setNext(null);
function copyAttrs(names, source, dest) {
for (var i = 0; i < names.length; ++i) {
var name = names[i];
var value = source.attr(name);
if (value) dest.attr(name, value);
}
}
function replace(replaceClass, withClass) {
var found = $(replaceClass, element);
var replacement = element.find(withClass);
if (found.length == 0) {
replacement.remove();
return;
}
// if additional attributes need to be copied from the placeholder
// to the dropdown, they can be added here
copyAttrs(['tabindex'], found, replacement);
found.replaceWith(replacement);
$compile(replacement) (scope);
};
replace('.vehicleYear', '.selectYear');
replace('.vehicleMake', '.selectMake');
replace('.vehicleModel', '.selectModel');
replace('.vehicleTrim', '.selectTrim');
scope.years.load();
},
templateUrl: appConfig.templateRoot + '/vehicleSelector.html'
};
}
]);
});