SharePoint Framework: Multiple webpart instances within the same page Angular2

In August 2016, I’ve added a quick guide to how to build an angular2 webpart using the awesome new -back then- SharePoint framework
http://www.sharepointtweaks.com/2016/08/sharepoint-framework-angular2-sample.html also it was basically to demonstrate what can be done in a context of a github issue https://github.com/SharePoint/sp-dev-docs/issues/7

As Andrew Connell pointed out it’s rather an angular limitation , which if we search for any work around , we can easily find that there is a workaround shared by Christoph Krautz here https://github.com/angular/angular/issues/7136 

Sounds easy right. However, trying out this workaround in the SPFx world isn’t that straight forward. You will get an error as the first dependency of your AppModule  is not recognized by CompileMetadataResolver

AppModule  is not recognized by CompileMetadataResolver

AppModule  is not recognized by CompileMetadataResolver

My first thought was, how can I get the componentFactoryResolver without even passing it. I’ve used the _componentFactoryReolver member of the ApplicationRef object

 	var resolver: ComponentFactoryResolver = appRef['_componentFactoryResolver'];

view rawComponentFactoryResolver hosted with ❤ by GitHub

Now I can create the Factory and update the selector to match the webpart ID.
My second problem is how to distinguish different webparts if I passed the selector to the module constructor it will have the same value for all the webparts on the page. which leads also to only single bootstrapped webpart.
I’ve added an id to the main component to use it in addition to the tagName as selector and used the description field to represent the id value
However, that didn’t solve the problem as the value injected to the AppModule constructor was the same.

AppModule constructor

AppModule constructor

What to do next?? I ran out of ideas, not really I came up with a stupid one but it works  instead of the selector I’ve passed the Document object and in the consturctor I’ll search all the elements that matches the webpart main component selector and voila!

 	public render(): void {
 	this.domElement.innerHTML = '<my-app id="' + this.properties.description + '">loading 1...</my-app>';
 	var selector = 'my-app#' + this.properties.description;
 	var platform = platformBrowserDynamic([
 	{ provide: BOOTSTRAP_COMPONENTS_TOKEN, useValue: this.domElement.ownerDocument }
 	]);
 	platform.bootstrapModule(AppModule);
 	}

 

view rawwebpart.ts hosted with ❤ by GitHub
 	export class AppModule {
 	constructor(
 	@Inject(BOOTSTRAP_COMPONENTS_TOKEN) private document
 	) { }
 	 
 	ngDoBootstrap(appRef: ApplicationRef) {
 	 
 	this.document.querySelectorAll('my-app').forEach(element => {
 	var resolver: ComponentFactoryResolver = appRef['_componentFactoryResolver'];
 	const factory = resolver.resolveComponentFactory(App);
 	factory.selector = "my-app#"+element.id;
 	appRef.bootstrap(factory);
 	});
 	 
 	 
 	}
 	}

 

view rawapp.ts hosted with ❤ by GitHub

it works !

SharePoint Workbench

SharePoint Workbench

DISCLAIMER :  this is a hack for experiment purpose only I’m no Angular2 expert I’m actually learning how to use this thing at the moment of writing these words.

the code can be found https://github.com/ministainer/Angular2MultipleSampleSPFx

Reference:
Fouad, A. (2017). SharePoint Framework: Multiple webpart instances within the same page Angular2. [online] Sharepointtweaks.com. Available at: http://www.sharepointtweaks.com/2017/02/sharepoint-framework-multiple-webpart-angular2.html [Accessed 30 Nov. 2017].

 

Want to read more on the SharePoint Framework?

Download INTRODUCING SHAREPOINT ONLINE FOR DEVELOPERS the exclusive free chapter from the new book SharePoint Development with the SharePoint Framework by Jussi Roine and Olli Jääskeläinen.

Share this on...

Rate this Post:

Share: