Chapter 9. Implementing Unidirectional Functional Associations with Plain JS

Table of Contents

1. Implementing Single-Valued Reference Properties
2. Make a JS Class Model
3. New Issues
4. Code the Model
4.1. Summary
4.2. Code each model class as a JS class
4.3. Code the property checks
4.4. Code the property setters
4.5. Choose and implement a deletion policy
4.6. Serialization functions
5. Code the View
5.1. Setting up the Retrieve/List All user interface
5.2. Setting up the Create and Update user interfaces
6. Quiz Questions
6.1. Question 1: Single-valued reference property
6.2. Question 2: Implementing the CASCADE deletion policy
6.3. Question 3: JS class model

The three example apps that we have discussed in previous parts of this tutorial, the minimal app, the validation app, and the enumeration app, have been limited to managing the data of one object type only. A real app, however, has to manage the data of several object types, which are typically related to each other in various ways. In particular, there may be associations and subtype (inheritance) relationships between object types. Handling associations and subtype relationships are advanced issues in software application engineering. They are often not sufficiently discussed in text books and not well supported by application development frameworks.

A unidirectional functional association is either one-to-one or many-to-one. In both cases such an association is represented, or implemented, with the help of a single-valued reference property.

In this chapter, we show

  1. how to derive a plain JS class model from an OO class model with single-valued reference properties representing unidirectional functional associations,

  2. how to code the JS class model in the form of plain JavaScript model classes,

  3. how to write the view and controller code based on the model code.

1. Implementing Single-Valued Reference Properties

When coding a class, the ES2015 feature of function parameter destructuring allows using a single constructor parameter that is a record with a simplified syntax for defining its fields. We make use of this new feature for obtaining a simplified class definition syntax illustrated by the following example:

class Book {
  constructor ({isbn, title, year, ...}) {
    this.isbn = isbn;
    this.title = title;
    this.year = year;
    ...
  }
  ...
}

A single-valued reference property, such as the property publisher of the object type Book, allows storing internal references to objects of another type, such as Publisher. When creating a new object, the constructor function needs to have a parameter for allowing to assign a suitable value to the reference property. In a typed programming language, such as Java, we would have to take a decision if this value is expected to be an (internal) object reference or an (external) ID reference. In JavaScript, however, we can take a more flexible approach and allow using either of them, as shown in the following example:

class Book {
  constructor ({isbn, title, year,
      publisher, publisher_id}) {
    ...
    // assign object reference or ID reference
    if (publisher || publisher_id)  {
      this.publisher = publisher || publisher_id;
    }
    ...
  }
  ...
}

Notice that the record parameter's publisher field represents a JS object reference while its publisher_id field represents an ID reference. In JavaScript, we can use a disjunctive expression like expr1 || expr2 for getting the value of the first expression, if it is defined (and not 0), or else the value of the second expression. We handle the resulting ambiguity in the property setter by checking the type of the argument as shown in the following code fragment:

set publisher(p) {
  var publisher_id = "";
  // p can be an ID reference or an object reference 
  publisher_id = (typeof p !==  "object") ? p : p.name;
  ...
  this._publisher = Publisher.instances[ publisher_id];
  ...
}

Notice that the name of a publisher is used as an ID reference, since it is the standard ID of the Publisher class.