# Using GoJS with Angular

Examples of most of the topics discussed on this page can be found in the gojs-angular-basic project, which serves as a simple starter project.

If you are new to GoJS, it may be helpful to first visit the Getting Started Tutorial .

The easiest way to get a component set up for a GoJS Diagram is to use the gojs-angular package, which exports Angular Components for GoJS Diagrams, Palettes, and Overviews. More information about the package, including the various props it takes, can be found on the NPM page. Our examples will be using a GraphLinksModel, but any model can be used.

You can see a sample project using all GoJS / Angular Components here.

## General Information

### Installation

To use the published components, make sure you install GoJS and gojs-angular: `npm install gojs gojs-angular`.

### About Component Styling

Whether you are using a Diagram, Palette, or Overview `gojs-angular` component, you will probably want to style them. First, you'll need to style a CSS class for the div of your GoJS Diagram / Palette / Overview such as:

    /* app.component.css */
    .myDiagramDiv {
      background: whitesmoke;
      width: 800px;
      height: 300px;
      border: 1px solid black;
    }

To style the GoJS Diagram / Palette / Overivew div, which will reside in the `gojs-angular` component(s) you are using, make sure you set the `@Component` decorator's `encapsulation` propety to either `ViewEncapsulation.None` or `ViewEncapsulation.ShadowDown`. Without this, your styling will not effect the component divs. Read more about Angular view encapsulation here.

Your `@Component` decorator for the component holding the your GoJS / Angular Component(s) should look something like:

    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
      encapsulation: ViewEncapsulation.None
    })

Note: You may alternatively use the default `ViewEncapsulation.Emulated` value, if you assign additional CSS modifiers :host and ::ng-deep to your class selector. Be warned, however, ng-deep is technically deprecated, so this is not best practice.

## The DataSyncService

The `gojs-angular` package comes with an Angular service called DataSyncService, used to easily merge changes (a go.IncrementalData instance) with an Array of Node or Link Data, or a modelData object.

This service has three static functions:

- `syncNodeData(changes, array)` - Merges any node data changes in a go.IncrementalData object with a given array of node data, then returns the new array
- `syncLinkData(changes, array)` - Merges any link data changes in a go.IncrementalData object with a given array of link data, then returns the new array. Note: Ensure you set the linkKeyProperty if you are using GraphLinksModel, so data merging is possible.
- `syncModelData(changes, object)` - Merges any modelData changes in a go.IncrementalData object with a given modelData object, then returns the new object

These functions should allow you to keep your data synced up as needed, without needing to write lots of code.

### Listening for Model Changes

It is common to listen for data changes in a Diagram or Palette, then do something with those changes on an application-level (such as syncing those changes with app-level data). That's why, for both the DiagramComponent and PaletteComponent, there is a `modelChange` `@Input` property function. This is a prime example of where the DataSyncService can be used.

As of `gojs-angular` 2.0, Array / object `@Input` properties are assumed to be immutable. As such, when updating these properties, new Arrays / objects must be generated -- one cannot simply mutate an element of the Array or object. Please see the gojs-angular-basic project for examples of both maintaining state immutability and usage of the DataSyncService.

Note: The UndoManager should always be enabled to allow for transactions to take place, but its maxHistoryLength can be set to 0 to prevent undo and redo.

## The Diagram and Palette Components

The Diagram and Palette Components accept a similar set of `@Input` properties.

Diagram Component accepts:

- `initDiagram` - A function that must return a GoJS Diagram. You may define your Diagram's Node and Link templates here.
- `divClassName` - A class name for your Diagram div
- `nodeDataArray` - An array containing data objects for your nodes
- `linkDataArray` - An array containing data objects for your links. Optional.
- `modelData` - A data object, containing your diagram's model.modelData. Optional.
- `skipsDiagramUpdate` - A boolean flag, specifying whether the component should skip updating, often set when updating state from a GoJS model change.
- `modelChange` - A function, which accepts a go.IncrementalData object. This function will fire when your Diagram's model changes, allowing you to decide what to do with those changes. A common practice is to sync your app-level data to reflect the changes in the diagram model, which is made simple using the DataSyncService `gojs-angular` ships with.

The Palette Component accepts:

- `initPalette` - A function that must return a GoJS Palette. You may define your Palette's Node and Link templates here.
- `divClassName` - A class name for the div your Palette div
- `nodeDataArray` - An array containing data objects for your nodes
- `linkDataArray` - An array containing data objects for your links. Optional.
- `modelData` - A data object, containing your palette's model.modelData. Optional.

Because GoJS Palettes are read-only by default, there is no `modelChange` property in PaletteComponent. Since there won't be user-driven changes to a Palette's model, changes to node/link/model data should be achieved by immutably altering the analogous above @Input properties.

## Sample Diagram / Palette Component Usage

Here is an example of how one might set up their Diagram / Palette component properties

    // Big object that holds app-level state data
    // As of gojs-angular 2.0, immutability is required of state for change detection
    public state = {
      // Diagram state props
      diagramNodeData: [
        { id: 'Alpha', text: "Alpha", color: 'lightblue' },
        { id: 'Beta', text: "Beta", color: 'orange' }
      ],
      diagramLinkData: [
        { key: -1, from: 'Alpha', to: 'Beta' }
      ],
      diagramModelData: { prop: 'value' },
      skipsDiagramUpdate: false,

      // Palette state props
      paletteNodeData: [
        { key: 'PaletteNode1', color: 'firebrick' },
        { key: 'PaletteNode2', color: 'blueviolet' }
      ]
    }; // end state object

    public diagramDivClassName: string = 'myDiagramDiv';
    public paletteDivClassName = 'myPaletteDiv';

    // initialize diagram / templates
    public initDiagram(): go.Diagram {
      const $ = go.GraphObject.make;
      const dia = $(go.Diagram, {
        'undoManager.isEnabled': true,
        model: $(go.GraphLinksModel,
          {
            nodeKeyProperty: 'id',
            linkKeyProperty: 'key' // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
          }
        )
      });

      // define the Node template
      dia.nodeTemplate =
        $(go.Node, 'Auto',
            $(go.Shape, 'RoundedRectangle', { stroke: null },
              new go.Binding('fill', 'color')
            ),
            $(go.TextBlock, { margin: 8, editable: true },
              new go.Binding('text').makeTwoWay())
          );
      return dia;
    }

    /**
     * Handle GoJS model changes, which output an object of data changes via Mode.toIncrementalData.
     * This method should iterate over thoe changes and update state to keep in sync with the FoJS model.
     * This can be done with any preferred state management method, as long as immutability is preserved.
     */
    public diagramModelChange = function(changes: go.IncrementalData) {
      console.log(changes);
      // see gojs-angular-basic for an example model changed handler that preserves immutability
      // when setting state, be sure to set skipsDiagramUpdate: true since GoJS already has this update
    };

    public initPalette(): go.Palette {
      const $ = go.GraphObject.make;
      const palette = $(go.Palette);

      // define the Node template
      palette.nodeTemplate =
        $(go.Node, 'Auto',
          $(go.Shape, 'RoundedRectangle', { stroke: null },
            new go.Binding('fill', 'color')
          ),
          $(go.TextBlock, { margin: 8 },
            new go.Binding('text', 'key'))
        );

      palette.model = $(go.GraphLinksModel,
        {
          linkKeyProperty: 'key'  // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
        });

      return palette;
    }

Once you've defined your `@Input` properties for your components, pass these properties to your DiagramComponent and PaletteComponent in your template, like so:

    <gojs-diagram
      [initDiagram]='initDiagram'
      [nodeDataArray]='state.diagramNodeData'
      [linkDataArray]='state.diagramLinkData'
      [modelData]='state.diagramModelData'
      [skipsDiagramUpdate]='state.skipsDiagramUpdate'
      (modelChange)='diagramModelChange($event)'
      [divClassName]='diagramDivClassName'>
    </gojs-diagram>

    <gojs-palette
      [initPalette]='initPalette'
      [nodeDataArray]='state.paletteNodeData'
      [divClassName]='paletteDivClassName'>
    </gojs-palette>

You will now have a GoJS Diagram and Palette working in your Angular application. Again, for a full example of a `gojs-angular` application, see gojs-angular-basic.

## Using the Overview Component

The Overview Component accepts the following Angular `@Input()` properties.

- `initOverview` - A function that must return a GoJS Overview.
- `divClassName` - A class name for your Overview div
- `observedDiagram` - The GoJS Diagram this Overview observes

Define these properties in the component that will hold your Overview Component, like:

    public oDivClassName = 'myOverviewDiv';
    public initOverview(): go.Overview {
      const $ = go.GraphObject.make;
      const overview = $(go.Overview);
      return overview;
    }
    public observedDiagram = null;

Then pass these properties to your Overview Component in your template, like:

    <gojs-overview
      [initOverview]='initOverview'
      [divClassName]='oDivClassName'
      [observedDiagram]='observedDiagram'>
    </gojs-overview>

But, we're not done yet. `observedDiagram` is null, so the Overview won't observe anything. To assign your Overview a Diagram to observe, you will have to reassign the `observedDiagram` property after initialization. To do so, reassign the bound `observedDiagram` property in your component holding your Overview Component in the `ngAfterViewInit` lifecycle hook.

Note: To avoid a `ExpressionChangedAfterItHasBeenCheckedError`, you must inform Angular to then detect changes. This can be done with the ChangeDetectorRef.detectChanges() method. You can inject a ChangeDetectorRef instance into your wrapper Component constructor, and use that after you alter `observedDiagram` to call detectChanges(). Like so:

    constructor(private cdr: ChangeDetectorRef) { }

    public ngAfterViewInit() {
      if (this.observedDiagram) return;
      // in this snippet, this.myDiagramComponent is a reference to a GoJS/Angular Diagram Component
      // that has a valid GoJS Diagram
      this.observedDiagram = this.myDiagramComponent.diagram;

      // IMPORTANT: without this, Angular will throw ExpressionChangedAfterItHasBeenCheckedError (dev mode only)
      this.cdr.detectChanges();
    }

Now, after initialization, your Overview should display appropriately.

## Updating Properties Based on App State

You may have some app-level properties you want to affect the behavior / appearance of your Diagram, Palette, or Overview. You could subclass their respective components and add `@Input` bindings with specific setter methods, or, more simply, you can have an `ngOnChanges` function in your app-level component that updates various Diagram / Palette / Component properties based on your app state.

For example, say you have an app-level property called `showGrid`. When `showGrid` is true, your Diagram's grid should be visible -- when false, it should be invisible. In your AppComponent, you could do something like:

    // myDiagramComponent is a reference to your DiagramComponent
    @ViewChild('myDiagram', { static: true }) public myDiagramComponent: DiagramComponent;

    public ngOnChanges () {
      // whenever showGrid changes, update the diagram.grid.visible in the child DiagramComponent
      if (this.myDiagramComponent && this.myDiagramComponent.diagram instanceof go.Diagram) {
        this.myDiagramComponent.diagram.grid.visible = this.showGrid;
      }
    }

## Migrating to 2.0

This page assumes use of `gojs-angular` version 2.0, which requires immutable state, unlike previous versions. It is recommended to use the 2.0 version. If you have a `gojs-angular` project using an earlier version of the package, migrating to version 2.0 should be straightforward.

Update your `package.json` to require `gojs-angular` version 2.0 or greater, then run `npm install`

The biggest change with 2.0 is you must enforce immutability of `@Input` properties to your Diagram and Palette components. So, for instance, whenever an entry of `diagramNodeData` is updated, removed, or changed, you will need to generate a whole new Array. This can be done in many different ways with many different packages. To see some samples of this, see gojs-angular-basic, particularly the `modelChange` property of the Diagram Component.

Additionally, PaletteComponent no longer supports `skipsPaletteUpdate` or `modelChange` properties. As GoJS Palettes are read-only by default, their models should not be changing based on user input. Instead, if you need to update their node/link/model data, update their @Input properties (immutably, of course).

GoJS