DMN.io VIEW DMN AND EDIT DMN IN angular appilcation

Hi,

I need some examples to guide how to use DMN.io in angular, may be something like tutorial videos.

Thanks,
Manish

We do not have something like that, but it was asked in the forum before.

html

<div #ref class="editor-container"></div>

In your compoent.ts import DMN Modeller. Pl. see the following

import {  Component,  EventEmitter,  OnInit,  ViewChild,  ElementRef,  AfterViewInit,  ViewContainerRef} from '@angular/core';

import DmnModeler from 'dmn-js/dist/dmn-modeler.development.js';
import propertiesPanelModule from 'dmn-js-properties-panel';
import propertiesProviderModule from 'dmn-js-properties-panel/lib/provider/camunda';
import drdAdapterModule from 'dmn-js-properties-panel/lib/adapter/drd';
import * as camundaModdleDescriptor from 'camunda-dmn-moddle/resources/camunda.json';

@Component({
  selector: 'your-decision-diagram-selector',
  templateUrl: './your-decision-diagram-modeller.component.html',
  styleUrls: ['./your-decision-diagram.component.scss']
 
})
export class YourDecisionModellerComponent implements OnInit, OnDestroy, AfterViewInit {

  private dmnDiagramModeler: DmnModeler; // DMN Modeller
  private importDone: EventEmitter<any> = new EventEmitter(); // Fires as soon as  DMN Modeller, importing XML is success

  @ViewChild('ref', { static: false }) private el: ElementRef; // host for Decision Diagram


  constructor() {
    // initialize DM Diagra Modeller
    this.dmnDiagramModeler = new DmnModeler({
      keyboard: { bindTo: window },
      drd: {
        additionalModules: [propertiesPanelModule, propertiesProviderModule, drdAdapterModule]
      },
      moddleExtensions: {
        camunda: camundaModdleDescriptor
      }
    });

    // fires when XML Import into DMN Modeller is complete
    this.dmnDiagramModeler.on('import.done', ({ error, warnings }) => {
      console.log('Import Done event successfully emitted');
      if (!error) {

        const activeEditor = this.dmnDiagramModeler.getActiveViewer();
        const canvas = activeEditor.get('canvas');
        canvas.zoom('fit-viewport');
        activeEditor.attachTo(this.el.nativeElement);

        // DMN Canvas will have multiple views (one view for each decision box/table)
        const view = this.dmnDiagramModeler.getViews()[0];
        this.dmnDiagramModeler.open(view);


        // PROPERTIES PANEL
        const prosPanel = activeEditor.get('propertiesPanel');
        // console.log('propertiesPanel == ', prosPanel);
        if (null != prosPanel) {
          // console.log('this.elProps', this.elProps);
          prosPanel.attachTo(this.elProps.nativeElement); // attach it to a ViewChild

        }

     
        // SWITCHING TABS
        this.dmnDiagramModeler.on('import.render.complete', (aNewView, err, wrngs) => {
     
        });
      }
    });
  }

  ngOnInit() {
    
  }

  ngAfterViewInit() {
    this.dmnDiagramModeler.on('views.changed', event => {
      console.log('View Changed event got fired.....event = ', event);
    });
  }

  ngOnDestroy() {
    // destroy DMNJs instance
    if (this.dmnDiagramModeler != null) {
      this.dmnDiagramModeler.destroy();
    }
  }
}

1 Like

Hi Mallesh,

Thanks for this code snippet.
However, I am new to Angular and still confused on how I would proceed from this.

I tried calling this.dmnDiagramModeler.importXML, but this kept failing. I downloaded a simple DMN specification from the demo modeler and hardcoded it as the argument for importXML.
I can see that the event fires, however I always get the following error: Error: "failed to parse document as <dmn:Definitions>"

Any suggestions for what I might be doing wrong?

The error means that the diagram could not be imported. What version of dmn-js are you using and what version of DMN is your diagram?

1 Like

Thanks for the quick answer.

When trying to figure out my DMN version, I realised I copy pasted the XML code incorrectly.
I had forgotten the <?xml ... ?> tag in the beginning. It is parsing correctly now.

The good news is however that I am now able to verify that Mallesh’s example works.
Would it be of any use for DMN.io if I created a more fleshed out example version, and placed it in a Git repo?

sharing working examples somewhere (e.g. on GitHub) is always a good idea! Feel free to create something like this and notify us / share it here in the forum. Maybe we can bring it on an example collection then.

As promised, here is a repository containing an example of using the dmn-js modeller in an Angular 9 application. (It probably works for other Angulars too)

I will probably update it in the future as I get to know the library better.

1 Like

I’m sorry… for delayed response. Did you get answer?

Hi mallesh,

I was able to implement it, and I shared it in the GitLab example above. :slight_smile:

Awesome… looked at your git hub, simple and to the point implementation. I’m trying to customize DMN Decision tables (drop down with auto suggestions for rule facts etc., )

Thanks! I never could have done it without your first code snippet. :slight_smile:

In the future I will also be looking into customizing them, mainly to color cells of the tables in different colors. Do you have any public code at which I could look if I need a starting point?

I don’t have one handy, but search for DMN Decision table customization. There are two ways

  1. Override Style sheet -> its a hack
  2. Better Approach: DMN uses inferno to render decision tables with multiple modules (Table header provider module, cell module etc.,). you need to override these provides and have your own way of rendering. This way you will have 100% handle of what/how is being rendered on the decision table.

I did write override code for table headers, i will post my code sometime today.

That would be awesome! Thanks in advance. :smiley:

import customPropertiesProviderModule from './decision-diagram-overrides/custom-properties/provider';
import DmnModeler from 'dmn-js/dist/dmn-modeler.development.js';
import propertiesPanelModule from 'dmn-js-properties-panel';

@Component({
  selector: 'jhi-decision-diagram',
  templateUrl: './decision-modeller.component.html',
  styleUrls: ['./decision-modeller.component.scss']
})
export class DecisionModellerComponent implements OnInit {

  private dmnDiagramModeler: DmnModeler;
  
  constructor( ) {
    this.dmnDiagramModeler = new DmnModeler({
      keyboard: { bindTo: window },
      drd: {
        additionalModules: [
          propertiesPanelModule,
          **customPropertiesProviderModule**,
          drdAdapterModule
        ]
      }});

decision-diagram-overrides/custom-properties/index.ts

import cmd from 'dmn-js-properties-panel/lib/cmd';
import translate from 'diagram-js/lib/i18n/translate';

import PropertiesPanel from 'dmn-js-properties-panel';

export default {
  __depends__: [cmd, translate],
  __init__: ['propertiesPanel'],
  propertiesPanel: ['type', PropertiesPanel]
};

decision-diagram-overrides/custom-properties/provider/index.ts

import IdeaManiCustomDmnPropertiesProvider from './ideamani-dmn-properties-provider';

export default {
  __init__: ['propertiesProvider'],
  propertiesProvider: ['type', IdeaManiCustomDmnPropertiesProvider]
};

decision-diagram-overrides/custom-properties/provider/ideamani-dmn-properties-provider.ts

'use strict';

import inherits from 'inherits';
import PropertiesActivator from 'dmn-js-properties-panel/lib/PropertiesActivator';
import idProps from 'dmn-js-properties-panel/lib/provider/dmn/parts/IdProps';
import nameProps from 'dmn-js-properties-panel/lib/provider/dmn/parts/NameProps';

function createGeneralTabGroups(element, translate) {
  const generalGroup = {
    id: 'general',
    label: translate('Properties'),
    entries: []
  };

  idProps(generalGroup, element, translate);
  nameProps(generalGroup, element, translate);

  return [generalGroup];
}

function IdeaManiCustomDmnPropertiesProvider(eventBus, translate) {
  PropertiesActivator.call(this, eventBus);

  this.getTabs = function(element) {
    console.log('element =====================>', element);
    const generalTab = {
      id: 'general',
      label: translate('Properties'),
      groups: createGeneralTabGroups(element, translate)
    };

    return [generalTab];
  };
}

IdeaManiCustomDmnPropertiesProvider.$inject = ['eventBus', 'translate'];
inherits(IdeaManiCustomDmnPropertiesProvider, PropertiesActivator);

export default IdeaManiCustomDmnPropertiesProvider;

Please visit this link. I ran into some issues and didn’t focus on solving it. Now i’m back to this topic, i will let you know if I get through this. But this can be used as an example to customize decision tables