14

Use-case: A client wants to build a library that consist of Angular 2 components but exposes abstracted, technology-agnostic interface to the end user (developer) of that library, so that those users might be using plain JavaScript and not be aware of the internals of the library.

The difficulty comes from the following:

  1. There is a page, which uses plain JavaScript. This page is developed by third-party.
  2. The third-party should be able to insert given Angular 2 component at specific places (DOM nodes) on the page.
  3. Let's say the component is <mg-input> and it should be shown in the header of the plain JavaScript page, but not only there - also in a form down the page. Two different places, two different DOM nodes which have between them plain html.

The question: How do we bootstrap component at specific DOM node and how do we pass configuration (not primitives but a complex object) to those components?

In the React world this is done simply by running ReactDom.render(domEl, <CustomInput nonPrimitiveConfig={config}/>) and depending on what domEl и config is, the component will be rendered in different places with different config.

How to do this in Angular 2?

antitoxic
  • 3,746
  • 1
  • 37
  • 46
  • 3
    The question has popped up [many](http://stackoverflow.com/q/41783547/1153681) [times](http://stackoverflow.com/q/41804873/1153681) on SO. Interestingly, under a very different wording every time. It boils down to wanting to use standalone Angular "widgets" in a non-Angular environment (be it a static HTML page, a page generated in plain JavaScript...). The accepted answer seems to be that this is impossible (unless you're willing to run a full Angular app per widget). Angular as it is is designed to control the entire page or a large portion of it, but not a bunch of spread out bits. – AngularChef Jan 27 '17 at 12:32
  • @AngularFrance by "full Angular app", do you mean `ngModule` or something else? – antitoxic Jan 29 '17 at 16:10
  • 1
    By "full Angular app", I mean the thing you bootstrap with `platformBrowserDynamic().bootstrapModule()`. (An app is a collection of NgModules.) – AngularChef Jan 29 '17 at 16:46
  • Well, you bootstrap a module that may import other modules :). Additional problem that comes from the question lies in the fact you cannot provide complex/non-primitive configuration for bootstrapped components unless you dynamically create a service/provider just for that purpose. – antitoxic Jan 30 '17 at 10:45
  • Late to the party, but my project is trying to do the same thing. Long story short, there is no way. For what you need, you do not want Angular. You need to hand-roll this code. Indeed, what you want is something like the various JQuery component libraries, which bootstrap a component from a static HTML doc. Sorry to say, you're building this yourself. – Aaron Martin-Colby Dec 29 '17 at 02:19

3 Answers3

1

You should be able to use Angular Elements to accomplish this. Angular Elements allows you to create a class that can be registered with most popular browsers as a custom element. The custom element can then be used just like any other DOM element, and includes Angular binding and change detection. Check this out for more details: https://angular.io/guide/elements

Edit: This functionality only exists for Angular 6+. If you are required to use Angular 2, this is not an option.

0

Maybe ask why they want Angular 2 components specifically?

We've coded a standalone "widget" consisting of a javascript API, UI and styling. The developer of an app calls a javascript function to trigger it.

Everything the dev needs is packaged with zero library dependencies.

Your alternative is to rather develop the components minus the UI (e.g. closures/SEF). The client app can then use whatever tech they want for the UI.

  • This not an option. It has already been discussed with the client. It also doesn't answer the question. – antitoxic Jan 30 '17 at 10:30
0

This is not possible with Angular until Custom Elements is added (which was announced Q4 2017 but the github repo has been archived for some reason, so I'm not sure if CE will continue to be developed).

What you could do is use Stencil to build your components. They are very similar (use typescript) to how you build components in Angular - such components can then be loaded by Angular itself (with some basic config) or any other framework or even in just a plain vanilla HTML/JS setup.

For example, here is a basic Stencil component.

The major difference to angular is that there is no separate template HTML file, but instead it uses JSX to render the template.

The 3rd party would be able to insert these components at a specific place.

Your developers could add the components to an Angular project for whatever purpose you need them to be in Angular.

rmcsharry
  • 5,363
  • 6
  • 65
  • 108