Table of Contents
A unidirectional non-functional association is either one-to-many or many-to-many. In both cases such an association is represented, or implemented, with the help of a multi-valued reference property.
In this chapter, we show
how to derive a JS class model from an OO class model with multi-valued reference properties representing unidirectional non-functional associations,
how to code the JS class model in the form of JavaScript model classes,
how to write the view and controller code based on the model code.
A multi-valued reference property, such as the property
Book
::authors
, allows storing a collection of
references to objects of some type, such as Author
objects.
When creating a new object of type Book
, the constructor
function needs to have a parameter for providing a suitable value for this
property. We can allow this value to be either a collection of internal
object references or of ID references, as shown in the following
example:
class Book {
constructor ({isbn, title, year, authors, authorIdRefs,
publisher, publisher_id}) {
this.isbn = isbn;
this.title = title;
this.year = year;
// assign object reference or ID reference
this.authors = authors || authorIdRefs;
if (publisher || publisher_id) {
this.publisher = publisher || publisher_id;
}
}
...
}
Notice that the constructor's parameter record is expected to
contain either an authors
or an authorIdRefs
slot. The JavaScript expression authors||authorIdRefs
, using
the disjunction operator ||
, evaluates to a map
authors
, if there is a slot with name authors
,
or to an array authorIdRefs
, otherwise. We handle the
resulting ambiguity in the property setter by checking the type of the
argument as shown in the following code fragment:
set authors( a) { this._authors = {}; if (Array.isArray(a)) { // array of IdRefs for (const idRef of a) { this.addAuthor( idRef); } } else { // map of IdRefs to object references for (const idRef of Object.keys( a)) { this.addAuthor( a[idRef]); } } }
In JS, a collection-valued reference property can be implemented in two ways:
having an array list (a JS array) of object references as its value,
having a map as its value, such that the values of the object's standard ID attribute are the keys, which are mapped to internal JS object references.
We prefer using maps for implementing set-valued reference properties since they
guarantee that each element is unique, while with an array we would have
to prevent duplicate elements. Also, an element of a map can be easily
deleted (with the help of the delete
operator), while this
requires more effort in the case of an array. However, for implementing
ordered or non-unique association ends corresponding to
ordered-collection-valued or
multi-set-valued (or bag-valued)
reference properties, we use JS arrays.