In an ongoing web project with Weather Underground, the Mediacurrent development team is breaking new ground with decoupled Drupal and Angular 2. The endeavor has required refactoring the Presentation Framework originally built for Weather.com from dependent on Angular 1 to being javascript framework agnostic. This blog series explores how Mediacurrent, in collaboration with the Angular team at Google, has solved for several architectural challenges.

Welcome to the third installment in our series on the wunderground.com project. Click here to read parts one and two.

As mentioned in our first post, refactoring the Presentation Framework originally built for weather.com to be javascript framework agnostic and work with Angular 2 presented us with some interesting challenges. Today, I’ll talk about the second big problem we encountered when building out this system - how do we allow the exact same component to be placed on a page multiple times?

By default, component definitions in Angular 2 are written with a ‘selector’ on which they inject their template. However as we began experimenting with ingesting these into CTools content types so that editors could place them onto panels pages, we realized there was no way for this selector to be dynamic.

@Component({
  selector: example-component,
  template: '<div> Hello, I am ng2 component 1 </div>',
})
export class exampleComponent {}

If we put the component above on the page once, when the page renders angular looks for the selector, ‘example-component’, and injects the template specified into it. Great! But if we put the same component on the page again, it will find the first instance of the selector and do its magic, but the second time it is bootstrapped it will *again* find that first instance of the selector and do the same. The second instance is ignored, and woe is us!

Luckily, the Angular team at Google came to our rescue. A permanent fix to this problem is on its way (github issue), but the team provided us with a workaround that moved us along. Here is a simple working example of the workaround code. The key piece of code in that Plunker is the function bootstrapWithCustomSelector(), which uses an injector factory to return a dynamic component loader. This allows us to redefine the component with our dynamic selector right before bootstrapping it.

In practice, we use an id attribute on our element that is a Drupal-generated uuid, which is then passed as a dynamic selector to our component at bootstrap time via Drupal.settings.

Once again, the responsive and collaborative support of Google’s team helped make our efforts a success! 

Additional Resources 
Building Wunderground.com with Drupal & Angular 2: How to Bootstrap (Challenge #1)
Building Wunderground.com With Drupal & Angular 2: An Introduction | Blog Post 
An Overview of Decoupled Drupal 8 | Video