First of all we’ll get it properly indented, to make it easier to understand what we’re looking at.
$("#b").click(function() {
var to_add = $("#t1").val();
$("#master").append("<option value='" + to_add + "'>" + to_add + "</option>");
$("#t1").val('');
$("#purchases").val(to_add);
});
$("#b1").click(function() {
$("#master option:selected").each(function() {
$("#purchases").append("<option>" + $(this).text() + "</option>");
$("#master option[value= '" + $(this).val() + "' ]").remove();
});
$('#purchases option').prop('selected', true);
});
$("#b2").click(function() {
$("#purchases option:selected").each(function() {
$("#master").append("<option>" + $(this).text() + "</option>");
$("#purchases option[value= '" + $(this).val() + "' ]").remove();
});
$('#purchases option').prop('selected', true);
});
$("#b3").click(function() {
$("#master option:selected").each(function() {
$("#salaries").append("<option>" + $(this).text() + "</option>");
$("#master option[value= '" + $(this).val() + "' ]").remove();
});
$('#salaries option').prop('selected', true);
});
$("#b4").click(function() {
$("#salaries option:selected").each(function() {
$("#master").append("<option>" + $(this).text() + "</option>");
$("#salaries option[value= '" + $(this).val() + "' ]").remove();
});
$('#salaries option').prop('selected', true);
});
We can now move out different values to strings, and attempt to come up with identical lines:
$("#b").click(function() {
var select = $("#master");
var field = $("#purchases");
var valueEl = $("#t1");
var to_add = valueEl.val();
select.append("<option value='" + to_add + "'>" + to_add + "</option>");
valueEl.val('');
field.val(to_add);
});
$("#b1").click(function() {
var source = $("#master");
var target = $("#purchases");
$("option:selected", source).each(function() {
target.append("<option>" + $(this).text() + "</option>");
$("option[value= '" + $(this).val() + "' ]", source).remove();
});
$('option', target).prop('selected', true);
});
$("#b2").click(function() {
var source = $("#purchases");
var target = $("#master");
$("option:selected", source).each(function() {
target.append("<option>" + $(this).text() + "</option>");
$("option[value= '" + $(this).val() + "' ]", source).remove();
});
$('option', source).prop('selected', true);
});
$("#b3").click(function() {
var source = $("#master");
var target = $("#salaries");
$("option:selected", source).each(function() {
target.append("<option>" + $(this).text() + "</option>");
$("option[value= '" + $(this).val() + "' ]", source).remove();
});
$('option', target).prop('selected', true);
});
$("#b4").click(function(){
var source = $("#salaries");
var target = "#master";
$("option:selected", source).each(function() {
master.append("<option>"+$(this).text()+"</option>");
$("option[value= '"+ $(this).val() + "' ]", source).remove();
});
$('option', source).prop('selected', true);
});
And we can now move some lines out to helper functions.
$("#b").click(function() {
var select = $("#master");
var field = $("#purchases");
var valueEl = $("#t1");
var to_add = valueEl.val();
select.append("<option value='" + to_add + "'>" + to_add + "</option>");
valueEl.val('');
field.val(to_add);
});
function moveOption(source, target) {
$("option:selected", source).each(function(option) {
target.append("<option>" + $(option).text() + "</option>");
$("option[value= '" + $(option).val() + "' ]", source).remove();
});
}
$("#b1").click(function() {
var source = $("#master");
var target = $("#purchases");
moveOption(source, target);
$('option', target).prop('selected', true);
});
$("#b2").click(function() {
var source = $("#purchases");
var target = $("#master");
moveOptions(source, target);
$('option', source).prop('selected', true);
});
$("#b3").click(function() {
var source = $("#master");
var target = $("#salaries");
moveOption(source, target);
$('option', target).prop('selected', true);
});
$("#b4").click(function() {
var source = $("#salaries");
var target = $("#master");
moveOption(source, target);
$('option', source).prop('selected', true);
});
The master switching back and forth between source and target, make it difficult to also refactor the line below moveOption that selects the option. A separate master variable is needed, so help us make better sense of things:
$("#b").click(function() {
var master = $("#master");
var field = $("#purchases");
var valueEl = $("#t1");
var to_add = valueEl.val();
master.append("<option value='" + to_add + "'>" + to_add + "</option>");
valueEl.val('');
field.val(to_add);
});
function moveOption(source, target) {
$("option:selected", source).each(function(option) {
target.append("<option>" + $(option).text() + "</option>");
$("option[value= '" + $(option).val() + "' ]", source).remove();
});
}
$("#b1").click(function() {
var master = $("#master");
var target = $("#purchases");
moveOption(master, target);
$('option', target).prop('selected', true);
});
$("#b2").click(function() {
var master = $("#master");
var source = $("#purchases");
moveOptions(source, master);
$('option', source).prop('selected', true);
});
$("#b3").click(function() {
var master = $("#master");
var target = $("#salaries");
moveOption(master, target);
$('option', target).prop('selected', true);
});
$("#b4").click(function() {
var source = $("#salaries");
var master = $("#master");
moveOption(source, master);
$('option', source).prop('selected', true);
});
We can now rename source/target to a more generic name of select.
$("#b").click(function() {
var master = $("#master");
var field = $("#purchases");
var valueEl = $("#t1");
var to_add = valueEl.val();
master.append("<option value='" + to_add + "'>" + to_add + "</option>");
valueEl.val('');
field.val(to_add);
});
function moveOption(source, target) {
$("option:selected", source).each(function(option) {
target.append("<option>" + $(option).text() + "</option>");
$("option[value= '" + $(option).val() + "' ]", source).remove();
});
}
$("#b1").click(function() {
var master = $("#master");
var select = $("#purchases");
moveOption(master, select);
$('option', select).prop('selected', true);
});
$("#b2").click(function() {
var master = $("#master");
var select = $("#purchases");
moveOptions(select, master);
$('option', select).prop('selected', true);
});
$("#b3").click(function() {
var master = $("#master");
var select = $("#salaries");
moveOption(master, select);
$('option', select).prop('selected', true);
});
$("#b4").click(function() {
var master = $("#master");
var select = $("#salaries");
moveOption(select, master);
$('option', select).prop('selected', true);
});
We can’t yet move the option select line out to the moveOption function, because we have two different types of move options. One moves to master, the other moves away from master.
$("#b").click(function() {
var master = $("#master");
var field = $("#purchases");
var valueEl = $("#t1");
var to_add = valueEl.val();
master.append("<option value='" + to_add + "'>" + to_add + "</option>");
valueEl.val('');
field.val(to_add);
});
function moveOption(source, target) {
$("option:selected", source).each(function(option) {
target.append("<option>" + $(option).text() + "</option>");
$("option[value= '" + $(option).val() + "' ]", source).remove();
});
}
function moveOptionToMaster(master, select) {
moveOption(select, master);
}
function removeOptionFromMaster(master, select) {
moveOption(master, select);
}
$("#b1").click(function() {
var master = $("#master");
var select = $("#purchases");
moveOptionToMaster(master, select);
$('option', select).prop('selected', true);
});
$("#b2").click(function() {
var master = $("#master");
var select = $("#purchases");
removeOptionFromMaster(master, select);
$('option', select).prop('selected', true);
});
$("#b3").click(function() {
var master = $("#master");
var select = $("#salaries");
moveOptionToMaster(master, select);
$('option', select).prop('selected', true);
});
$("#b4").click(function() {
var master = $("#master");
var select = $("#salaries");
removeOptionFromMaster(master, select);
$('option', select).prop('selected', true);
});
And now that the function properties are consistent, we can move the option select code in to the function too.
function moveOption(source, target) {
$("option:selected", source).each(function(option) {
target.append("<option>" + $(option).text() + "</option>");
$("option[value= '" + $(option).val() + "' ]", source).remove();
});
}
function moveOptionToMaster(master, select) {
moveOption(select, master);
$('option', select).prop('selected', true);
}
function removeOptionFromMaster(master, select) {
moveOption(master, select);
$('option', select).prop('selected', true);
}
$("#b").click(function() {
var master = $("#master");
var field = $("#purchases");
var valueEl = $("#t1");
var to_add = valueEl.val();
master.append("<option value='" + to_add + "'>" + to_add + "</option>");
valueEl.val('');
field.val(to_add);
});
$("#b1").click(function() {
var master = $("#master");
var select = $("#purchases");
moveOptionToMaster(master, select);
});
$("#b2").click(function() {
var master = $("#master");
var select = $("#purchases");
removeOptionFromMaster(master, select);
});
$("#b3").click(function() {
var master = $("#master");
var select = $("#salaries");
moveOptionToMaster(master, select);
});
$("#b4").click(function() {
var master = $("#master");
var select = $("#salaries");
removeOptionFromMaster(master, select);
});
To help clean up the first section of code, we can create an addOption function too.
function addOption(select, value) {
select.append("<option>" + value + "</option>");
}
function moveOption(source, target) {
$("option:selected", source).each(function(option) {
target.append("<option>" + $(option).text() + "</option>");
$("option[value= '" + $(option).val() + "' ]", source).remove();
});
}
function moveOptionToMaster(master, select) {
moveOption(select, master);
$('option', select).prop('selected', true);
}
function removeOptionFromMaster(master, select) {
moveOption(master, select);
$('option', select).prop('selected', true);
}
$("#b").click(function() {
var master = $("#master");
var field = $("#purchases");
var valueEl = $("#t1");
addOption(master, valueEl.val());
valueEl.val('');
field.val(to_add);
});
$("#b1").click(function() {
var master = $("#master");
var select = $("#purchases");
moveOptionToMaster(master, select);
});
$("#b2").click(function() {
var master = $("#master");
var select = $("#purchases");
removeOptionFromMaster(master, select);
});
$("#b3").click(function() {
var master = $("#master");
var select = $("#salaries");
moveOptionToMaster(master, select);
});
$("#b4").click(function() {
var master = $("#master");
var select = $("#salaries");
removeOptionFromMaster(master, select);
});
Those click functions can be made more sensible too, because there’s a clear connection between them.
function addOption(select, value) {
select.append("<option>" + value + "</option>");
}
function moveOption(source, target) {
$("option:selected", source).each(function(option) {
target.append("<option>" + $(option).text() + "</option>");
$("option[value= '" + $(option).val() + "' ]", source).remove();
});
}
function moveOptionToMaster(master, select) {
moveOption(select, master);
$("option", select).prop("selected", true);
}
function removeOptionFromMaster(master, select) {
moveOption(master, select);
$("option", select).prop("selected", true);
}
function initButtons({add, remove, target}) {
$(add).click(function() {
moveOptionToMaster(master, $(target));
});
$(remove).click(function() {
removeOptionFromMaster(master, $(target));
});
}
var master = $("#master");
$("#b").click(function() {
var valueField = $("#t1");
addOption(master, valueField.val());
$("#purchases").val(valueField.val());
valueField.val("");
});
initButtons({add: "#b1", remove: "#b2", target: "purchases"});
initButtons({add: "#b3", remove: "#b4", target: "#salaries"});```
And we’re now starting to get to something interesting.
As you can see it’s a process of gradual improvement. That’s the nice thing about refactoring. It about making small improvements over and over, that end up resulting in a large improvements.