Skip to main content

One post tagged with "angular"

View All Tags

· 3 min read
Simon Porritt

One of the core concepts when working with components in Angular is that of @Inputs and @Outputs. For instance, maybe you have some component that expects to be told what text to use as its title, and which will output an event when the user clicks a button:

@Component({    selector:"app-my-component",    template:`        <div>            <h1>{{title}}</h1>            <button class="btnEmit" (click)="emitEvent('test')">Click Me</button>        </div>        `})export class MyComponent {  @Input() title:string
  @Output() outputEvent = new EventEmitter<string>()
  emitEvent(value:string) {    this.outputEvent.emit(value)  }}

From version 5.6.2, the Toolkit's Angular integration now offers a couple of ways of working with these that earlier versions did not support.

Using @Input in a node component#

Imagine the component shown above was being used to render some node type in your UI - with a couple of small changes we can make it so:

import {BaseNodeComponent} from "@jsplumbtoolkit/browser-ui-angular"import {EventEmitter, Component, Input, Output} from "@angular/core"
@Component({  template:`          <div>              <h1>{{title}}</h1>              <button class="btnEmit" (click)="emitEvent('test')">Click Me</button>          </div>          `})export class NodeComponent extends BaseNodeComponent {  @Input() title:string
  @Output() outputEvent = new EventEmitter<string>()
  emitEvent(value:string) {    this.outputEvent.emit(value)  }}

We've removed selector from the Component spec, since it's not relevant when rendering via the Surface, and we've wired up the component to extend BaseNodeComponent, but other than that the component is the same as in the first example. Prior to version 5.6.2, this line:

@Input() title:string

would be ignored by the Toolkit. From 5.6.2 onwards, though, the Toolkit will attempt to set this input from the backing data for the node. So if, for instance, you had this data object for a node:

{  "id": "1",  "title": "My First Node"}

then the Toolkit will set "My First Node" on the title input. This is of course really just a form of syntactic sugar - you could just easily render the title in your template like this (remembering that obj is set on the component by the Toolkit when it creates it):


as you can by using the input on the class:


but if you're like me, you might find that the approach using @Input feels a little more nicely formalised.

Using @Output in a node component#

You can also now wire up listeners to @Outputs in your components. The process to do this involves providing a vertexEvent callback to the Surface component. For example, imagine you embed a surface component in one of your components:

<div class="my-component">    <h3>Here is my component</h3>    <jsplumb-surface surfaceId="surface"                   toolkitId="myToolkit"                   [view]="view"                   [renderParams]="renderParams"                  (vertexEvent)="vertexEvent($event)">    </jsplumb-surface></div>

Remember from above the @Output() outputEvent... declaration on the node component? Whenever that output emits something, the Surface will invoke vertexEvent:

import { Vertex } from "@jsplumbtoolkit/core"import { ComponentRef } from "@angular/core"
vertexEvent(detail:{    vertex:Vertex,     event:Event,     payload:any,     component:ComponentRef<any>}) {    }

The callback is given the Toolkit's vertex, the original event, the payload (ie. whatever was emitted from the output), and the Angular ComponentRef. You can access the specific Angular component via the instance field on this component ref.