Something to note about your function is that, when data.wasConsumed || data.wasCancelled
is false, the entire function does nothing. That means that we can move the condition to the top as a guard clause:
function (nRow, data, iDataIndex) {
if (!data.wasConsumed && !data.wasCancelled) {
return;
}
// The rest of the code...
With one thing to switch on, it's really straightforward. With two, as you have here, it's not quite so straightforward, but it's fairly easy to manage. As the conditions start to proliferate, though, there may be better strategies to take.
I might say that instead of using booleans to represent the different conditions, we could use a string status instead. This doesn't mean that data
has to lose the boolean properties (or even change at all, see below). data
could grow some behavior with a #status
method that returns a string status:
data.status = function() {
if(this.wasConsumed) {
return "consumed";
} else if(this.wasCancelled) {
return "cancelled";
} else {
return "";
}
};
Now, we could do something like:
function (nRow, data, iDataIndex) {
var status = data.status();
if (status.length === 0) {
return;
}
var $row = $(datatable.row(nRow).draw().node());
var $quantityInput = $row.find("input.quantity");
var rowClass;
$quantityInput.parent().append("<span>"+ $quantityInput.val() +"</span>");
$row.find("input, select").remove();
if(status === "consumed") {
rowClass = ".consumed";
} else if (status === "cancelled") {
rowClass = ".cancelled";
}
$row.addClass(rowClass);
}
We could even convert the second conditional into a case statement.
switch(status) {
case "consumed":
rowClass = ".consumed";
break;
case "cancelled":
rowClass = ".cancelled";
break;
}
But that's awfully verbose. We could use an object as a dictionary to map our statuses to classes:
var STATUS_CLASSES = {
"consumed": ".consumed",
"cancelled": ".cancelled"
};
//...
rowClass = STATUS_CLASSES[status];
This allows us to eliminate the conditional all together, and just use a configuration array. The astute reader might notice, though, that the status returned happens to match our class name that we are assigning, so we could also just do:
rowClass = "." + status;
This is the simplest, and because we decide the return value of #status
, we can guarantee this convention.
We may not always be in the position to change the data
object, though, and doing so may have other side effects. In this case, we have an alternate strategy: to make a status "factory." We could create an object (or even just a single function) that takes a data
object and returns a status object (just a string that is one of our statuses):
var DataStatus = {};
DataStatus.forData = function(data) {
if(data.wasConsumed) {
return "consumed";
} else if(data.wasCancelled) {
return "cancelled";
} else {
return "";
}
};
We can see that the implementation of the "factory" is almost exactly the same as the #status
method. We use it in a very similar manner. The final result of all this would look like:
function (nRow, data, iDataIndex) {
var status = DataStatus.forData(data);
if (status.length === 0) {
return;
}
var $row = $(datatable.row(nRow).draw().node());
var $quantityInput = $row.find("input.quantity");
var rowClass;
$quantityInput.parent().append("<span>"+ $quantityInput.val() +"</span>");
$row.find("input, select").remove();
rowClass = "." + status;
$row.addClass(rowClass);
}