Submitted by gwagner on
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 strings 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 2: Adding Constraint Validation, which is Part 2 of a five part tutorial about engineering front-end web applications with plain JavaScript.