Bpmn js and Angular JS 1.5

Hello everyone,
Is there an implementation of bpmn-js in Angularjs 1.5.

Thanks in advance.
Kind regards

1 Like

Hi,

Do not think there is one, unfortunately.

There is, however, an Chrome app example with an example of how to do that (can not judge how good it is, though):
repository
link to relevant file

Cheers,
Vladimir

1 Like

Hi,

I have an angular 1.5 implementation in this repository (instructions included). It’s based on an old version of BPMN-JS but it can help you as a starting guide.

Relevant files:
Angular app
Modeler
Viewer

Regards,
David

3 Likes

Hello David,
Thank you so much, I will check your implementation and let you know.

Kind regards,

Dhaker

1 Like

Hello David,

I can’t figure out how i can inject and instanciate my custom modeler in order to import the bpmn 2.0 xml
below the followed steps:

thank you in advance.

in the app.js:

    require('bpmn-js/lib/Modeler');
    require('./custom-modeler');
    global.jQuery = require('jquery');
    require('jquery-ui-dist/jquery-ui.js');	
    require('bootstrap');
    require('angular/angular');
    require('angular-route/angular-route');
    require('angular-ui-bootstrap');

    angular.module('app', ['ui.bootstrap', require('bpmn-js/lib/Modeler')]);
    require('./directives/myFlow.directive');

in myFlowDirective.js:

(function () {
	'use strict';
	angular.module('app').directive('myFlow', enformFlow);
	enformFlow.$inject = ['$window', 'CustomModeler'];

	function enformFlow($window, CustomModeler) {
		// Usage:
		//     <my-flow></my-flow>
		var directive = {
			link: link
			, restrict: 'EA'
			, replace: true
			, templateUrl: './templates/myFlow.template.html'
			, height: '='
			, width: '='
			, title: '@'
		}
		return directive;

		function link(scope, element, attrs) {
			var modeler = new CustomModeler({
				container: 'wrapper'
				, keyboard: {
					bindTo: document
				}
			});
			modeler.importXML(bpmnXML, function (err) {
				if (err) {
					console.error('something went wrong:', err);
				}
				modeler.get('diagram').zoom('fit-viewport');
				modeler.addCustomElements(customElements);
			});
			// expose bpmnjs to window for debugging purposes
			window.bpmnjs = modeler;
		}
	}
})();

error message:

angular.js:68 Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to:
Error: [$injector:modulerr] Failed to instantiate module function CustomModeler(options) due to:
Error: [$injector:unpr] Unknown provider: options
http://errors.angularjs.org/1.5.8/$injector/unpr?p0=options
at http://localhost:9013/app.js:9842:12
at http://localhost:9013/app.js:14285:19
at getService (http://localhost:9013/app.js:14438:39)
at injectionArgs (http://localhost:9013/app.js:14462:58)
at Object.invoke (http://localhost:9013/app.js:14484:18)
at http://localhost:9013/app.js:14396:45
at forEach (http://localhost:9013/app.js:10095:20)
at loadModules (http://localhost:9013/app.js:14375:5)
at http://localhost:9013/app.js:14392:40
at forEach (http://localhost:9013/app.js:10095:20)
http://errors.angularjs.org/1.5.8/$injector/modulerr?p0=function%20CustomMo…0%20%20at%20forEach%20(http%3A%2F%2Flocalhost%3A9013%2Fapp.js%3A10095%3A20)
at http://localhost:9013/app.js:9842:12
at http://localhost:9013/app.js:14414:15
at forEach (http://localhost:9013/app.js:10095:20)
at loadModules (http://localhost:9013/app.js:14375:5)
at http://localhost:9013/app.js:14392:40
at forEach (http://localhost:9013/app.js:10095:20)
at loadModules (http://localhost:9013/app.js:14375:5)
at createInjector (http://localhost:9013/app.js:14297:19)
at doBootstrap (http://localhost:9013/app.js:11532:20)
at bootstrap (http://localhost:9013/app.js:11553:12)

Hi Dhaker,

You can include the Modeler as a constant, like here. For you case,

var customModeler = require('./custom-modeler'); // for readability
// (...)
angular
    .module('app', ['ui.bootstrap'])
    .constant('CustomModeler', customModeler);
require('./directives/myFlow.directive');

Regards.

1 Like

Kudos to you David, you save my day :slight_smile:

Best regards,

David,
just for clarification, in your example are you using the window object to inject your constants so they could be globally accessed?

(function() {
  "use strict";
  angular
    .module('custom-bpmnjs', [
      // Angular modules
      'ngAnimate',
      'ngAria',
      'ngMessages',
      // 3rd Party Modules
      'ui.router',
      'ui.bootstrap',
      'ngStorage',
      'pascalprecht.translate',
      'toaster'
    ])
    .constant('Modeler', window.BpmnJSCustom.Modeler)
    .constant('Viewer', window.BpmnJSCustom.Viewer)
    .constant('PropertiesProviders', window.BpmnJSCustom.PropertiesProviders);
})();

Hi Dhaker,

Yes, they’re already globally available. Indeed, you could access to them with $window, e.g.

(function () {
    'use strict';
    angular.module('app').directive('myFlow', enformFlow);
    enformFlow.$inject = ['$window'];

    function enformFlow($window) {
        // even window.CustomModeler works
        var CustomModeler = $window.CustomModeler; 
	// Usage:
	//     <my-flow></my-flow>
	var directive = {
		link: link

But, these ways are considered bad practices

1 Like

Hello David,
Thank you again, Injecting vendor library thru constant is working well and it’s a good workaround, however, i’m facing an issue below a screenshoot:
What i am trying to perform is:

  1. integrating the bpmn js custom viewer within an Angular JS directives,
  2. Include the directive to a popup based on bootstrap modal

Any clue to resolve this issue :slight_smile:

(function () {
	'use strict';
	angular.module('app').directive('myFlow', myFlow);
	myFlow.$inject = ['$window', 'CustomModeler'];

	function myFlow($window, CustomModeler) {
		// Usage:
		//     <my-flow></my-flow>
		var directive = {
			link: link
			, restrict: 'EA'
			, replace: true
			, template: '<div id="wrapper1" title="My Flow Editor"></div>'
			, height: '='
			, width: '='
			, title: '@'
		}
		return directive;

		function link(scope, element, attrs) {
			var modeler = new CustomModeler({
				container: 'wrapper1'
				, keyboard: {
					bindTo: document
				}
			});
			modeler.importXML(bpmnXML, function (err) {
				if (err) {
					console.error('something went wrong:', err);
				}
				modeler.get('wrapper1').zoom('fit-viewport');
				modeler.addCustomElements(customElements);
			});
			// expose bpmnjs to window for debugging purposes
			window.bpmnjs = modeler;
		}
	}
})();

Best regards,

Error message:

VM390:1 POST http://fake.com/ net::ERR_BLOCKED_BY_CLIENT(anonymous function) @ VM390:1(anonymous function) @ VM390:1
angular.js:13920 TypeError: Cannot read property ‘appendChild’ of null
at CustomModeler.Viewer._createContainer (http://localhost:9013/app.js:44591:9)
at CustomModeler.Viewer (http://localhost:9013/app.js:44287:25)
at CustomModeler.Modeler (http://localhost:9013/app.js:44041:10)
at new CustomModeler (http://localhost:9013/app.js:991:11)
at Object.link (http://localhost:9013/app.js:1132:18)
at http://localhost:9013/app.js:11028:18
at invokeLinkFn (http://localhost:9013/app.js:19715:9)
at nodeLinkFn (http://localhost:9013/app.js:19116:11)
at http://localhost:9013/app.js:19454:13
at processQueue (http://localhost:9013/app.js:26164:28)

Sure, man.

You need to wait the DOM to render. Use $timeout.

(function () {
	'use strict';
	angular.module('app').directive('myFlow', myFlow);
	myFlow.$inject = ['$window', '$timeout', 'CustomModeler'];

	function myFlow($window, $timeout, CustomModeler) {
		// Usage:
		//     <my-flow></my-flow>
		var directive = {
			link: link
			, restrict: 'EA'
			, replace: true
			, template: '<div id="wrapper1" title="My Flow Editor"></div>'
			, height: '='
			, width: '='
			, title: '@'
		}
		return directive;

		function renderModeler(){
			var modeler = new CustomModeler({
				container: 'wrapper1'
				, keyboard: {
					bindTo: document
				}
			});
			modeler.importXML(bpmnXML, function (err) {
				if (err) {
					console.error('something went wrong:', err);
				}
				modeler.get('wrapper1').zoom('fit-viewport');
				modeler.addCustomElements(customElements);
			});
			// expose bpmnjs to window for debugging purposes
			window.bpmnjs = modeler;
		}

		function link(scope, element, attrs) {
			var that = this;
			$timeout(function(){
				renderModeler.call(that);
			}, 0);
		}
	}
})();

I didn’t test it, but it’s the idea of how to use the $timeout function.

1 Like

Hello David,
Thank you, I will try that :slight_smile:

Hello David,
Unfortunately , the same error persist, although the DOM has finished rendring, but the exception occurs in
http://localhost:9013/node_modules/bpmn-js/lib/Viewer.js class,

  1. Initially the parent object was set to the wrapper1 ( template: '<div id="wrapper1" title="My Flow Editor" </div>')

  1. In the next line, the parent object is flushed after being passed to the domQuery

    Viewer.prototype._createContainer = function(options) {

    var parent = options.container,
    container;

    // support jquery element
    // unwrap it if passed
    if (parent.get) {
    parent = parent.get(0);
    }

    // support selector
    if (isString(parent)) {
    parent = domQuery(parent);
    }

    container = domify(’

    ’);

    assign(container.style, {
    width: ensureUnit(options.width),
    height: ensureUnit(options.height),
    position: options.position
    });

    parent.appendChild(container);

    return container;
    };

Do you have any clue?

Best regards,

Hi Dhaker,

That occurs because,

var modeler = new CustomModeler({
			container: 'wrapper1'

should be,

var modeler = new CustomModeler({
			container: '#wrapper1'

domQuery works with jQuery selectors syntax.

Regards

2 Likes

Hi David,

That make sense, but a new error message occurs (check below screenshoot):

thanks a ton friend :smiley:.

:confused:

This seems to be a problem of your custom modeler more than Angular. Have you tested it in a non-angular environment? Can you share a larger fragment of your code?

1 Like

Hello Bpmn js Team and David,
Thank you so much, You always point me to the right direction to solve my issues.

I’m hardly trying to display within a bootstrap modal popup the bpmn js diagram which is wrapped within a n Angular JS directive:

  1. the red region (div id: palette) will hold the palette,
  2. the gray region (div id: diagram) will contain the diagram,

but as you can see the layout is messed up :grin::
Below link for the code source, can you please take a look,any guidance or recommandation to perform this implmentation are welcomed.

https://drive.google.com/file/d/0B5ruioHjOasTc0s4VXM4UTdBZTg/view?usp=sharing

Thank you again.

Hi Dhaker,

Without doing a deep review, I’d suggest changing in the file ./app/directives/enformFlow.directive.js (L:45-47)

var modeler = new CustomModeler({
			//container: '#wrapper'
			container: targetElement[0] // here

to

var modeler = new CustomModeler({
			//container: '#wrapper'
			container: targetElement[0].querySelector("#diagram")
1 Like

Thank you very much David, i already set it as below and it’s working like a charm :smile:

var modeler = new CustomModeler({
			 container: "#diagram'

Have you any clue how to move the palette to the red region (div id: palette) (as mentioned in this post by Vladimirs i need to override the init method )

kudos to you team, i’really appreciate your collaboration and dedication.

Hi dhaker,

I see that this topic was closed some time ago. Did you finish the implementation? It would be very useful if I could have access to the final code. I’m working on a similar project.
:slight_smile: