In this article, we’ll be discussing how to create and load multiple Angular 2 web parts on a page in SharePoint 2013. We’ll address the following items to create our solution:
As of this writing, Angular 2 is in Release Candidate 4. It’s possible (or perhaps even likely) some of the functionality and steps detailed in this article will change. We’ll assume knowledge of SharePoint 2013 development tasks, including how to update master pages and add web parts.
One of the most difficult questions when starting a project is what template or starter solution to begin with. In this article, I started with a combination of the Angular 2 Quickstart and Dan Wahlin’s Angular2-JumpStart. The Angular 2 Quickstart gives the extreme basics needed to start an Angular 2 application and doesn’t include much of the unnecessary functionality for web parts, such as routing. Dan’s Angular2-JumpStart gives us a good beginning on the necessary functionality for bundling.
For our file structure, we’ll create the following basic folders and files (the link to the final source code can be found at the bottom of this article):
As the final step of manipulating the data, we loop through all possible combinations of leaders and status values while counting up matching records in our data retrieved from the REST calls. This data goes into our seriesData array.
We have our typical files necessary for an Angular 2 application, including package.json, tsconfig.json, typings.json and the node_modules folder. We keep our primary source code within the src folder with all Angular 2/TypeScript code in the app subfolder.
Notice that in our completed file structure, we have systemjs.config.js and index.html files in both the root folder and the src folder. The files in the src folder are used for debugging and bundling the code. The files in the root folder can be used to test our bundled files that will be created in the dist folder.
Before we go too deep into our solution, we need to review the goals for our solution and the challenges we must overcome. Our goals:
Based on these goals, we run into several challenges. Most Angular 2 examples are created as single-page applications. Because an Angular 2 application is bootstrapped to one HTML tag (such as within the Angular 2 Quickstart), we can’t create a single application that encompasses all web parts. Instead, we must create multiple applications. We’ll create an Angular application for each web part.
If you have any code or subfolders in the src/app folder (such as those you might create via the Angular 2 Quickstart tutorial), remove them.
We need a location to store our web part code, so we’ll create a folder under src/app titled wp1. Create a file in the wp1 folder named wp1.component.ts. This file will contain the code for our web part. The contents of this file should be as follows:
This simplistic code will create an h1 heading and will display “Web Part 1 Loaded” in the heading once Angular has loaded and processed the code.
Next we create a main.ts file under the wp1 folder. This will be the entry point for the Angular application within our web part. The contents of this file should be as follows:
Here, we’re importing our component file created before, then bootstrapping the application with this component.
Next, we’ll update our systemjs.config.js file within our src folder. We use the file created within the Angular 2 Quickstart as a starting point. We need to update the map and packages section to include the new wp1 code (and remove the app sections as we removed the app code before). Our systemjs.config.js file should now look like the following:
Next, we need to update the index.html file from the Angular 2 Quickstart within the src folder to include our wp1 files and the selector tag for the web part (and again remove any references to app from the Quickstart code). When completed, the index.html file will contain the following:
At this point, we have a working solution with one web part. Next, we’ll step through how to debug our application via NPM.
We’ll use NPM scripts to test and debug the solution we’ve created so far. The scripts available to run are defined in the package.json file under the scripts section:
Note that “npm start” also runs the start script. Because of the watch and browser-sync functionality, code can be edited, and the browser window will refresh when code is changed.
Through the browser window, functionality can be tested to make sure it works as expected. Also, be sure to check developer tools in Internet Explorer or Google Chrome to ensure no unexpected errors are being thrown to the console. Exit the terminal command to end debugging and browser-sync.
Once we’re sure our code is working, we should follow the steps under the “Adding web part code” section to add wp2 as a duplicate of wp1. Be sure to change every section referring to web part 1 in the steps above to web part 2.
After all updates are made, run “npm start” again. At this point, you should see the following in your browser window:
While early beta versions of Angular 2 enabled production mode by default, the most recent versions have production mode turned off by default. This requires us to specify that we want to use production mode.
When production mode is off, additional change detection and deep object comparisons run to help detect bugs that will cause issues later in production. In order to enable production mode, it’s recommended to include the enableProdMode function call just before the application is bootstrapped. This would change our wp1/main.ts to the following:
Since we want to make sure production mode is turned on for every web part, it’s tempting to add this code to the main.ts file for each web part. However, if we do this, we get the following error:
Cannot enable prod mode after platform setup.
This error occurs because the one global platform object is created and shared for all Angular applications that occupy the same browser window. Once bootstrap has been run once, no additional configuration to this global platform object can be made. For more details on bootstrapping, see the official Angular documentation on the bootstrap function.
Instead, we should break this functionality into a separate folder on the same level as wp1 (called prodMode) and add a main.ts with the following code:
We must also add the definitions for the new prodMode code within the map and packages section of our systemjs.config.js file. We won’t import the prodMode code via our index.html file since we’re using that file for our debugging, and production will use different HTML to bootstrap the web parts.
Our goal with bundling is to create four different files. We’d like one file for each web part (wp1.min.js and wp2.min.js). We want one file to turn on production mode (prodMode.min.js) so that we can load that separately from any individual web part. The fourth file is the common.min.js file. This file will contain all of the Angular 2 code and other third-party node_module code. We’ll also set this file up to contain any common code between web parts 1 and 2. This will allow us to load only the necessary code for a page, depending on whether one or both web parts are used on a page.
We create a bundle.js file to handle the bundling. This bundle.js file uses SystemJS Builder to create the bundles we define. Let’s take a look at the code and then walk through the pieces:
We’ll start the bundle process using either “npm start bundle” for a development bundle (non-minified, non-mangled) or “npm start bundle:prod” for a production bundle (minified, mangled).
After ensuring we have SystemJS Builder loaded, we load the systemjs.config.js file for configuration.
Next, we’ll build our bundle of common files, which will contain the Angular 2 source and other node_module files. We start with the following line of code:
This sets our file for output based on whether we have specified this build as a production build or not.
Next, we build the bundle file using the builder.bundle method.
The first argument for the method “(wp1 & wp2)” uses bundle arithmetic to identify all common code between web part 1 and web part 2. Bundle arithmetic is similar to set theory. For more details about how this works, see the Bundle arithmetic section for SystemJS Builder. We use this to create the output file with minification, mangling and other properties set based on whether we’re creating a production build.
We follow the same concepts as above to build the prodMode, wp1 and wp2 files. The major difference between these and the common bundle is the bundle arithmetic. As an example, the bundle arithmetic for wp1 in a production build would be:
This gets all of the dependencies and files needed for web part 1, then removes everything we included in our common bundle. This ensures no code is repeated between the wp1 bundle and the common bundle.
Within this document library, we create two folders: vendor and dist. The vendor file includes the files and structure for all of the polyfills listed in the Angular 2 QuickStart (shim.min.js, zone.js, reflect.js, system.src.js). It’s recommended to keep the folder structure under node_modules the same in order to prevent confusion in the future as the polyfills are updated. The dist file will contain our bundled files that were created in the dist folder previously.
Next, we need to create a master page to include the polyfills, as well as our common and prodMode bundles. For ease of use, copy the seattle.html file in the Master Page Gallery, then rename the file as seattleAngular.html. Add the following lines of code just before the end of the head tag. Note that the code below is for a SharePoint site at /sites/a2webpart.
Save the updated master page, upload it to the Master Page Gallery, then set the master page for the site to the seattleAngular master page. (Note that this loads Angular on each page in the site. Another option to load Angular only on specific pages would include using the PlaceHolderAdditionalPageHead control on a Page Layout.)
Next, we’ll create our systemjs.config.js and place it in the root of the SiteAssets document library. This will contain the following:
This SystemJS configuration file sets up all of the mappings needed to point references to the proper bundle.
For the individual web parts, we’ll use the content editor web part and a text file to hold the contents for the web part. Create a wp1.txt file in the root of the SiteAssets document library and add the following code:
This code will link to the wp1 bundle, add our selector the web part will use for the Angular application, then import and run the web part 1 code (including the bootstrap function). We now only need to add the content editor web part and link to the text file under the Content Link setting to display the Angular application web part.
We can now duplicate the steps for web part 2 and the wp2 bundle to display both web parts on the same page.
Hopefully, after all of these steps, you’ve learned how to create and add multiple Angular 2 web parts onto a page in a SharePoint 2013 environment. While this is a starting point and works today, updates to Angular 2 may affect how this solution works in the future.