Properties Panel reading custom properties of user tasks

After a drag&drop of a user task with custom properties into the diagram, I try to access its Extensions tab to set values.

However, the properties panel will only read the custom properties of the dropped user task after saving and reopening the diagram.

Is this expected behavior or could it be due to missing configuration on my side?

On the screenshot you see the diagram xml at the moment the user task is dropped, and the Extensions tab which doesn’t show the two custom properties which visible in the source xml. If I save and reopen this diagram, the Extensions tab will show the two fields with their respective values - 0 and empty string.

For further assistance, please share a CodeSandbox that reproduces your issue in a way that we can inspect it. Without knowing your setup and your implementation, it will be hard to help you.

I’m trying to add the Properties Panel not directly but by calling a method from an Angular service which imports bpmn-js and the Properties Panel.

I keep getting an error

Cannot read property ‘depends’ of undefined

(those are two underscores on each side, your forum software converts them to bold formatting) This is an error I don’t receive with identically written code in my real non-codesandbox environment. I assume it’s because of not specifying types for the properties “moddle”, “modeling” and “propertiesPanel” in bpmn.service.ts, but I do not know what types should I give those.

Can you suggest the cause or the solution for this, so I can get the Modeler running with a Properties Panel enabled?

Codesandbox here: custom-elements-properties-panel-no-service (forked) - CodeSandbox

I tried foregoing the Angular service, instead trying to add the Properties Panel directly into my diagram component, only to get the same error message I was getting when using the Angular service, and which is shown above. I seem to be unable to import the Properties Panel in an Angular application in codesandbox. Please advise.

What confuses me about your sandbox example: where do you define the container for the Modeler and the Properties Panel? It seems you try to attach them at a later point in time, but I don’t see the exact place.

Btw.: there are late discussions in regards to integrating the properties panel into an Angular application: Error while using bpmn-js-properties-panel and camunda-bpmn-moddle in angular10 application. Did you already read through those threads?

Btw.: there are late discussions in regards to integrating the properties panel into an Angular application: Error while using bpmn-js-properties-panel and camunda-bpmn-moddle in angular10 application. Did you already read through those threads?

I’ve read through it on an earlier occasion, but it’s not relevant to my case now. My angular app does allow importing json modules. You can confirm that by checking out the tsconfig.json in the codesandbox.

I have cleaned up the codesandbox code a little, to make it more readable.

where do you define the container for the Modeler and the Properties Panel?

The containers are defined in the lines immediately after declaring the class:

@ViewChild("diagramContainer", { static: true }) private diagramContainer: ElementRef;
@ViewChild("propertiesPanelContainer", { static: true }) private propertiesPanelContainer: ElementRef;

Codesandbox forces the new line before “private”.

The modeler is attached in the ngAfterViewContentInit():

this.bpmnJS.attachTo(this.diagramContainer.nativeElement);

The Properties Panel is not being attached yet, because the app begins crashing as soon as I uncomment the lines:

   // additionalModules: [propertiesPanelModule, propertiesProviderModule],
   // moddleExtensions: {
   //   camunda: camundaModdleDescriptor
   // }

This error, which I’ve quoted in my post above, is the problem that I am experiencing only on codesandbox, and it prevents me from demonstrating my actual issue to you - “Cannot read property ‘depends’ of undefined”.

You can reproduce it by uncommenting the four lines I’ve quoted just above this paragraph. I have to work around this error before I can demonstrate the issue with the Properties Panel not updating its Extensions tab to display the custom properties of a drag&dropp-ed user task.

So the error indeed is coming from the fact the sandbox has problems importing bpmn-js-properties-panel and bpmn-js-properties-panel/lib/provider/camunda, which resolve to undefined.

However, to tackle your original question, let’s forget Angular for now:

  • How does your custom properties for the user tasks look like? Cf. moddle descriptors
  • You’re speaking from drag&drop: how is your custom palette provider look like?
  • Any other custom modules you are providing?

This does not depend on Angular, but on the custom bpmn-js modules you provide. Would it be possible to share those with us? Maybe we are able to reproduce your original issue outside of your angular application, and inside a much simpler bpmn-js application.

Hint: properties not being displayed in the Properties Panel can be caused by not using modeling commands. The Properties Panel will be rerendered after a command has being fired or on reload the whole application. Maybe your Palette action is not doing it properly.

  • How does your custom properties for the user tasks look like? Cf. moddle descriptors

They are in the screencap in the original post. My moddle descriptor is the camunda-bpmn-moddle/resources/camunda.json The “caminda:property” is I guess this:

{
      "name": "Property",
      "superClass": [
        "Element"
      ],
      "properties": [
        {
          "name": "id",
          "type": "String",
          "isAttr": true
        },
        {
          "name": "name",
          "type": "String",
          "isAttr": true
        },
        {
          "name": "value",
          "type": "String",
          "isAttr": true
        }
      ]
    },

The properties are being read by the Properties Panel if the diagram is saved and reopened, which I guess points that it’s not a problem of unrecognized custom properties.

  • You’re speaking from drag&drop: how is your custom palette provider look like?

I am dragging items not from a custom palette (although I’ve customized the palette to hide some things from it) but from a list outside of the diagram parent element.

The list of draggable items is returned from an API response, and when dragging begins, the elements receive their diagram-compatible shape.

A draggable list item looks like this in the template:

<mat-tree-node
    class="leaf-node"
    [class.is-on-diagram]="node.isOnDiagram"
    *matTreeNodeDef="let node"
    [draggable]="!node.isOnDiagram"
    (dragstart)="dragStartHandler($event, node)"
    [matTooltip]="node.isOnDiagram ? 'Already used on the diagram' : ''">
    <fa-icon class="leaf-icon" leaf icon="grip-lines"></fa-icon>
    <span class="leaf-title">{{node.name}}</span>
  </mat-tree-node>

And on a dragStart event, this is the dragStartHandler() function definition:

dragStartHandler(dragEvent: DragEvent, element: ElementDefinition) {
    const definition = `{
      "type": "bpmn:${element.camundaActivityType}",
      "name": "${element.name.replace('\\', '\\\\')}",
      "bpmnActivityId": "${element.bpmnActivityId}",
      "calledElement": "${element.calledElement}",
      "calledProcessId": "${element.calledProcessId}"
    }`;
    const bpmnDefinition = JSON.parse(definition);
    const elementFactory = this.bpmnService.getElementFactory();
    const initialShape = elementFactory.createShape(bpmnDefinition);
    const create = this.bpmnService.getCreate();

    if (bpmnDefinition.type === 'bpmn:CallActivity') {
      this.bpmnService.addExtensionElements(
        initialShape, element, bpmnDefinition).subscribe((diagramElement) => {
        create.start(dragEvent, diagramElement);
      });
    } else {
      const diagramElement = this.bpmnService.generateDiagramElement(initialShape, element, bpmnDefinition);
      create.start(dragEvent, diagramElement);
    }
  }

Hopefully I’ll be able to show you all this in action in the workshop today.

For user tasks, the bpmnService.generateDiagramElement() would be called, which will generate the js object useful for the diagram, in accordance with the bpmnDefinition which is provided, along with the custom properties. Here is how this function looks:

public generateDiagramElement(elementShape, diagramElement: ElementDefinition, bpmnDefinition) {
    const newExtensionElements = this.moddle.create('bpmn:ExtensionElements');
    newExtensionElements.values = [];
    const suppliedVariables = [...diagramElement.workflowVariables];
    const newProperties = this.moddle.createAny('camunda:properties');
    newProperties.$children = [];
    const suppliedProperties = [...diagramElement.workflowProperties];

    suppliedVariables.forEach(variable => {
      const newVariable = this.moddle.createAny('camunda:in');
      if (variable.name === 'businessKey') {
        newVariable.businessKey = variable.value;
      } else {
        newVariable.target = variable.name;
        newVariable.sourceExpression = variable.value;
      }
      newExtensionElements.values.push(newVariable);
    });

    suppliedProperties.forEach(property => {
      const newProperty = this.moddle.createAny('camunda:property');
      newProperty.name = property.name;
      newProperty.value = property.value;
      newProperties.$children.push(newProperty);
    });

    newExtensionElements.values.push(newProperties);

    this.modeling.updateProperties(elementShape, {
      extensionElements: newExtensionElements,
    });

    elementShape.businessObject.name = bpmnDefinition.name;
    elementShape.businessObject.id = bpmnDefinition.bpmnActivityId;
    elementShape.businessObject.calledElement = bpmnDefinition.calledElement;

    return elementShape;
  }