In all application domains, there are enumeration datatypes that define the possible values of enumeration attributes. For instance, when we have to manage data about persons, we often need to include information about the gender of a person. The possible values of a gender
attribute are restricted to one of the following: "male", "female", or "undetermined". Instead of using these string
s as the internal values of the enumeration attribute gender
, it is preferable to use the positive integers 1
, 2
and 3
, which enumerate the possible values. However, since these integers do not reveal their meaning (the enumeration label they stand for) in program code, for readability we rather use special constants, called enumeration literals, such as GenderEL.MALE
and GenderEL.FEMALE
, in program statements like this.gender = GenderEL.FEMALE
. Notice that, by convention, enumeration literals are all upper case.
We can implement an enumeration in the form of a special JavaScript object definition using the Object.defineProperties
method:
var GenderEL = null;
Object.defineProperties( GenderEL, {
MALE: {value: 1, writable: false},
FEMALE: {value: 2, writable: false},
UNDETERMINED: {value: 3, writable: false},
MAX: {value: 3, writable: false},
labels: {value:["male","female","undetermined"], writable: false}
});
Notice how this definition of an enumeration takes care of the requirement that enumeration literals like GenderEL.MALE
are constants, the value of which cannot be changed during program execution. This is achieved with the help of the property descriptor writable:false
in the Object.defineProperties
statement.
This definition allows using the enumeration literals GenderEL.MALE
, GenderEL.FEMALE
and GenderEL.UNDETERMINED
, standing for the enumeration integers 1
, 2
and 3
, in program statements. Notice that we use the convention to suffix the name of an enumeration with "EL
" standing for "enumeration literal".
Having an enumeration like GenderEL
, we can then check if an enumeration attribute like gender
has an admissible value by testing if its value is not smaller than 1
and not greater than GenderEL.MAX
, as in:
Person.checkGender = function (g) {
if (!g) {
return new MandatoryValueConstraintViolation(
"Gender must be provided!");
} else if (!util.isPositiveInteger(g) || g > GenderEL.MAX) {
return new RangeConstraintViolation(
"Gender must be a positive integer " +
" not greater than "+ GenderEL.MAX +" !");
} else {
return new NoConstraintViolation();
}
};
Notice how the range constraint defined by the enumeration GenderEL
is checked: it is tested if the input value g
is a positive integer and if it is not greater than GenderEL.MAX
.
In the user interface, an output field for an enumeration attribute would display the enumeration label, rather than the enumeration integer. The label can be retrieved in the following way:
formEl.gender.value = GenderEL.labels[this.gender];
For user input to a single-valued enumeration attribute like Person::gender
, a radio button group could be used if the number of enumeration literals is sufficiently small, otherwise a single selection list would be used. If the selection list is implemented with an HTML select
element, the enumeration labels would be used as the text content of the option elements, while the enumeration integers would be used as their values.
For user input to a multi-valued enumeration attribute, a checkbox group could be used if the number of enumeration literals is sufficiently small, otherwise a multiple selection list would be used. For usability, the multiple selection list can only be implemented with an HTML select
element, if the number of enumeration literals does not exceed a certain threshold, which depends on the number of options the user can see on the screen without scrolling.
This blog post has been extracted from JavaScript Front-End Web Apps Tutorial Part 3: Dealing with Enumerations, which is Part 3 of a six part tutorial about engineering front-end web applications with plain JavaScript.