documentationfor yFiles for HTML 3.0.0.1

Logic Abstraction

The yFiles for HTML API is designed to make extensive use of logic encapsulation and abstraction. When you can’t find a property to set for object composition, the API provides numerous callbacks that allow developers to customize default behavior without subclassing. These callbacks are implemented as properties, typically using delegates, predicates, or other functional constructs. By setting these callbacks, you can inject custom logic directly into the default workflows of the API. This approach offers a flexible and lightweight alternative to inheritance for many customization scenarios.

For example, the following code snippet prevents nodes from being deleted when they still have edges connected to them:

// Prevent deletion of nodes that are connected to other nodes
graphEditorInputMode.deletablePredicate = (item) => {
  if (item instanceof INode) {
    if (graph.edgesAt(item).size !== 0) {
      return false
    }
  }
  return true
}
// Prevent deletion of nodes that are connected to other nodes
graphEditorInputMode.deletablePredicate = (item: IModelItem): boolean => {
  if (item instanceof INode) {
    if (graph.edgesAt(item).size !== 0) {
      return false
    }
  }
  return true
}

If a callback isn’t available, you can often derive from the class and override a protected method to change the behavior of the default implementation.

An example of this is the use of the factory method pattern in yFiles for HTML. In situations where a property should not be changed after the object is constructed, overriding the factory method provides a way to use a different implementation. One example is the UndoEngine of the Graph, which can only be customized by the createUndoEngine factory method.

In most cases, however, this pattern is provided in addition to object composition, and changing a property is uncommon. Also, you might want to initialize the object to the correct value instead of setting the property after construction to avoid unexpected behavior when changing the value.

Although setting the property value is sufficient in most cases, overriding the factory method has some advantages:

  • Lazy initialization of the property’s value: the value is only initialized when it’s needed.
  • Proper initialization order

In these cases, it’s beneficial to favor inheritance over object composition, and a factory method is provided in addition to the property.