Angular: Dynamically load template for a component

Created on 18 Mar 2017  ·  194Comments  ·  Source: angular/angular

I'm submitting a
[X] feature request

I have a component which provides some generic business logic. Let's say:

  • CRUD functionality
  • Productmanagement (product catalogue)
  • Cross department business management (separate layout for each department)
  • ...

Depending on a condition I want to show a layout (template) which is specific for a type of product, related to the user department, etc.
Right now I can't load a template on the fly for doing this.
I have read through all the issues here and on stackoverflow for possible ways on doing this.

The most practicabel way is the ngTemplateLayout. But in real life if you have dozens of different layout types, it blows up your template file and make unmaintenable.

If you use the dynamiccomponentloader which is the most recommend way by the angular team, it adds an huge overhead of code for generating the component dynamically, even if the functionality for component and module creation is encapsulated. In addition it doesn't allow a real generic solution, because in the ngModule which has also be created dynamically you have to provide all imports, exports, providers, ... to make the component work. So if you don't want to have a huge overhead in your generic component builder, you have to implement a generic componentbuilder for each "type" of your form types. Which is not practicable and increases the danger of recoding all after the next angular release

Expected behavior
Provide a way of loading a template dynamically for a component. As it is available in Angular 1
Please don't be dogmatic on this issue and consider supporting real world requirements in Angular 2
Thanks

core feature

Most helpful comment

I know the template can't be dynamic right now and that's a pain as I outlined. I don't want to implement two, more or hundreds of components with the same logic.
That's why I request this feature!

All 194 comments

Why not just have two components then load on whatever one corresponds to the situation that you need. For example: AdminDisplayComponent and NotAdminDisplayComponent?.
It's not possible to make templates dynamic, a template must be tied to a component

I know the template can't be dynamic right now and that's a pain as I outlined. I don't want to implement two, more or hundreds of components with the same logic.
That's why I request this feature!

@KarlXOL What I mean by it not being possible is that it would be impossible to make it dynamic without breaking AOT.
As for a solution to your problem, if you want to share common code then why not use a service? or if you don't think a service will do make a component then inherit from it

@DzmitryShylovich: I know you don't want to provide this feature. But as I tried to explain all other ways for doing this, are crutches and not practicable.
If I do this by using angular features, I have also to use the compiler which also breaks AOT-capability. Right? So what.
Please, don't be dogmatic and rethink your approach. I/we are providing solutions and need a platform which is supporting us in doing this.

@Toxicable : If you have an example on how to encapsulate e.g. CRUD functionality in a service, I'd like to see. Even if this possible there is the need for implementing for each e.g. product a component.

@KarlXOL I do not understand why CRUD functionality could not be implemented as a service. Probably it is the best way how to do it and a common pattern.

If I understand correctly that you do not care about AOT at all and you want to do all in JIT mode with Compiler module loaded in runtime. Then you can do it right now. Look at for eaxmple at https://www.ag-grid.com/ag-grid-angular-aot-dynamic-components, https://eyalvardi.wordpress.com/2016/09/04/injecting-components-in-runtime or even http://blog.assaf.co/angular-2-harmony-aot-compilation-with-lazy-jit-2.

@mlc-mlapis : Of course the actual data operations (new, update, etc.) are in a service. But they get triggered by user interactions (click, ...) which are part of a component.

The link you are referring to, just shows how deal with multiple components. And that's the point, I don't want to have multiple components for red, green, blue. I just need one component and change the template/layout. In my feature request I've explained why

@KarlXOL But this example is exactly what you want, yes or no (to understand your point of view)? https://eyalvardi.wordpress.com/2016/09/04/injecting-components-in-runtime

Right, the clicks, ... are there but do not understand why you mention them because your components inject the service through DI (it should be a singleton) and will provide a necessary interface.

Of course the actual data operations (new, update, etc.) are in a service. But they get triggered by user interactions (click, ...) which are part of a component.

@mlc-mlapis This is one of the possible solutions I refer to in my request ( "dynamiccomponentloader"). The downside of this approach is
1) it requires to much additional lines of code for each component which has dynamic content
2) the dynamic module creation needs to adapted (imports) to make it work (directives)
As a consequence you have a dynamic module with a huge overhead or you implement several dynamic module builders

In summary this solution is to heavy-weight, very low-level, risky that id needs to adapted as angular evolves,... and it is not competitive to the lean, quick approach Angular 1 provides for this requirement.
Just imagine you want to present a different "title" for users belonging to different departments to give just a imple example.

That's why I request the feature to change/load the template on the fly. The framework should deal with this low level stuff, not the business application.

It is clear now what you mean. I can imagine that type of simplification and having so high level of functionality. It is also necessary say that this would be strictly limited only for JIT mode.

Actually there is not any attribute in Angular which would differenciate its functionalities between JIT and AOT mode. There are stable, experimental, depreciated.

Another question is the priority of such functionality in timeline and the standpoint of Angular core team.

@mlc-mlapis Thanks for your feedback. I'm happy I was able to bring the message across :-)

I know from many other issues here, stackoverflow, there is a big need for this feature as it is a very common requirement in real business applications. In the past and even more in the future.

@DzmitryShylovich I can't see from the ng-descendant proposal it will be a solution for my request.

I'd recommend you rethink the angular architectural approach to make it more flexible and usable for big enterprise application scenarios. It can't be an impossible mission for the angular framework and team to load templates dynamically for a component.

@KarlXOL Enterprise application scenarios are the reason why AOT exists. 😄 The dynamic templates are just shortcuts and a cheaper solution. So probably the recommendation about rethinking that is unrealistic.

@mlc-mlapis I expected an answer like this. The more I'm wondering why the angular team isn't providing what is needed by enterprises. And making applications faster and cheaper is key in enterprise environment. But you confirmed this is not what you are supporting with angular 2.

@KarlXOL Just out of curiosity, do you have any info about and how Google develops its global applications?

@mlc-mlapis Not sure about. Is it Angular 1 or Angular 2??

@KarlXOL Because this isn't the only thing needed by enterprises, just because it's something you want to do doesn't mean it's something that everyone needs. Everything they have done lately is to make applications faster and easier to make applications, just take a look at the bundle reductions from v2 -> v4.
I would suggest rethinking how you're trying to accomplish your goal, methods that worked in AngularJS aren't always the best approach when working in Angular.

cc @robwormald

@KarlXOL No, I meant the most of made-in Google on Internet. Look at: https://medium.freecodecamp.com/how-google-builds-a-web-framework-5eeddd691dea#.4n6z26xx0

@KarlXOL here's is a small example I made https://plnkr.co/edit/kz2XKSKWSWZhPoncDQhG?p=preview
All you'd do with this is provide the UI/config then hook into the methods to hit the backend

@Toxicable I appreciate your plunker. My implementation looks like this. This part of the application is not related to the actual problem as I explained in my initial post.

@Toxicable You are right. My post was inaccurate regarding the service.

@KarlXOL I don't get what you want then. I don't see how being able to swap out templates on the fly can be any better than using a generic setup like this. Since with this you only have to defined a component which is only 20 LOC

@mlc-mlapis Thanks for your lessin in web development. As you mentioned it is about how google develop web frameworks. I have to admit that my request is from a perspective on how to provide business solutions for enterprises and how to utilize tools and frameworks for doing this. In addition to developing frameworks as you mentioned there arise some other requirements and needs. I'd appreciate if you would also give these kind of requirements some valuation. At the end, we all would benefit more from each other and angular 2 could be a more powerful framework.

@Toxicable Your sample is not about swapping out templates on the fly but for providing a data access service All other implementations for swapping templates (which is not supported actually) is done by dynamic module/component creation, which is much more complicated and low-level angular implementation.

@KarlXOL Yes I know, my sample wasn't about swapping out templates at all. You said:

If you have an example on how to encapsulate e.g. CRUD functionality in a service, I'd like to see. Even if this possible there is the need for implementing for each e.g. product a component.

This is what I did. I provided a solution to your problem, not in the way you wanted to solve it, but it's a solution none the less. However, my point remains; I don't see what you're gaining by having templates swapped in and out if it were somehow possible, in both cases you'd still have to write the template code, so what exactly do you gain for the largely extensive amount of work it would take to get even close to implementing something like this in the framework?

@Toxicable Exact. You got the point. I only have to write the template code. All the other code remains unchanged!! Imagine the general implementation of a master data management, including your service from above. Just change the template and another table (business object) is implemented. At least this is possible in Angular 1.

@KarlXOL And this is a problem in reality if you apply that principe in a large scope. Because you can not make proper tests as a lot of code is compiled at runtime, so you can find a lot of hidden errors only at runtime. And this is unacceptable. You can play with that concept only in a small scale and still you will risc a lot of unpredictability.

Just change the template and another table (business object) is implemented.

@mlc-mlapis Sure, you are a right. But consequently you have to remove the compiler from angular 2 then, because in principle I can already achieve what I want to do. It's just way too complicated.

I overstress your argument, but it includes also all kind of data (database, etc.) you are processing with an application. You can't test everything and there will always be something left to the responsibility of an application manager.
Back to our discussion, what is needed - in my opinion - is good mix of pragmatism and architectural vision. The vision is given, that's for sure. And some pragmatism could also be a win for angular 2. My requirement is not exotic and needed by many people out there.

@KarlXOL I can agree with some of your arguments. But on the other side I see also places on your side where you should re-think your application concepts simply because you will get better apps.

We are probably on the end of our discussion because the standpoint of Angular core team is important from this point of view. I just wanted to express some background arguments why AOT is a prefered way now.

I agree with KarlXOL's option. In my company's requirements, there are so much UIs need dynamic configure. It worked fine in angular 1. When I migrate angular1 to angular2, it become terrible. Finally, I found DynamicComponentLoader and use it to resolve the problems. But the performance is not acceptable along with as much as more customers complain recently.

I made discussion in my company. Most of developers in my company think Angular2 did a lot of static(controllable) things. It limited developer to work with dynamic things, like dynamic template, dynamic change language etc. I personally think It will lost flexibility. I also strong recommend angular 2 provide these of kind of dynamic functionality more easily to approach.

Why do you need different templates instead of different components? Perhaps you are missing that it is possible to inherit components in Angular? See here https://medium.com/@amcdnl/inheritance-in-angular2-components-206a167fc259 for example

Thanks for your recommend. But the solution is not what I want. My scenario is the view templates are configured dynamically by designer or non-developer and it was saved in database. The logic are fixed in most of situation. Just the requirement which want redesign layout or add/minus fields.
It is very common behavior in CRM/ERP domain. like odoo to drag-drop fields to generate difference form for difference industries.

OK. Then the only problem you have to do is to compile a user defined template as you described to a new component ... on the server of course ... which creates a new module that contains that new component ... save a flag to some configuration that says ... this details should be rendered by that new component ... and on demand load the new module in the right moment.

@mlc-mlapis
if you read this feature request and thread carefully you'll find out that it is to have a better solution as the one you are proposing and also to avoid the pain and mess involved with this solution approach.
@robert-luoqing explained very good the very common scenario and need for this feature.

@KarlXOL I know. The only moment I don't understand is that the only JiT dynamic compilation of custom templates is already available today and it always was here ... but the formulations above say that this feature is missing.

It is clear that they can't use AoT then and they probably understand why they can't.

So the only things which are on the table are some more user friendly Angular APIs to do those dynamic templates compilation in JiT mode, right? Even without compatibilty to the AoT mode.

@mlc-mlapis
I need to provide working, maintenable solutions to support business needs. Angular 2 is a framework which lays the foundation to this by providing very sophisticated software technologies. That's why I'm (still) using it.
On the other hand angular is missing some "user friendliness" to supports very common requirements. As the one we are discussing here for example. Room for improvements also exists for error messages (dev and runtime), UI-Framework, etc.

Being able to provide solutions is more import to me than what you are always taking about: AoT, static type checking, tree shaking, .... !!! (e.g. JIT usually is fast enough)
I understand this is important of course but sometimes I've the impression you are foregetting what is needed out there by "normal" developers.

OK, then we are understanding each other. The other things are priorities and general opinions on what is and is not important for different types of projects because there are hundreds possible cases.

This feature would be awesome. I have similar requirements on the ERP project I am working on, and unfortunately, only because of it, I can't use Angular, as much as I would like to.

I also endorse this feature.
We have an enterprise content management system where we serve pages from database. End users can modify HTML file using HTML text editor, and can perform n number of tasks.
We want to re-develop our client application using Angular, but this feature is stopping us.

@asadmalik3 You can have dynamic HTML fine, you just cant easily use Dynamic templates. Recall that templates are simply JS code, not HTML and for them to be run in AOT they need to be compiled.
Therefore, for a a CMS type system if you allow the user to edit the HTML without adding in any new Angular components, pipes, directives or services then you can do that 100% fine. You can even use existing components at run-time and replace them with the compiled working components in your application. And example of this is angular.io see https://github.com/angular/angular/blob/master/aio/src/app/layout/doc-viewer/doc-viewer.component.ts
Things have changed in Angular from AngularJS for the better, with things like AOT your applications with be much faster and provide a better user experience but in situations you just need to think about the problem in another light rather than expecting it to work exactly the same as it did before.

@Toxicable what is the performance effect of creating components on the fly? we have developed a sample of creating components on the fly and want to evaluate its performance before using it in production.

The first thing to consider is Dependancies. Creating components on the fly with different dependancies can cause issues.
Secondly when you compile Angular code in your browser you will use 100% of your users processor.
Thirdly you will forever be tired to the slow and big JIT Compiler
You can see this by running your application in JIT mode.

@Toxicable Just wondering how do we pass dependencies to a component created on the fly?
Is it the responsibility of the component creating it? Can you show me a decent example of it?

We have the same needs. Simply we allow our customer to organize the visual display of data in any way they want. WE USE THE SAME ANGULAR COMPONENTS, we just need to reorganize the HTML for each client. We have 100's of clients that have 10-20 roles, each role can have a unique layout, SAME ANGULAR components. But we have hundreds of unique HTML templates which use common Angular components. This isn't uncommon. We have looked at dynamically creating the forms using Angular, and that may work, but having the HTML template cached and ready is much faster. We'll look at dynamically creating not only the HTML but putting into a Component which will have to be dynamically derived, but I'm not holding up hope that it will perform. So, if an HTML template contains the same, exact Angular artifacts (dependencies, components, whatever) it seems reasonable that I should be able to swap out the template to get a new layout.

@asadmalik3 You pass the parent Injector down to the components created on the fly so they can use any of the services that already exist. If you want to have new Services then you need to load in a Module

@glwbkfs You can do exactly what you mention already, angular.io does exactly that. They use the same Angular components just organized in different ways in each of the content pages which at runtime the html for those components is swapped out for preexisting running components.
An example can be seen here https://github.com/angular/angular/blob/master/aio/src/app/layout/doc-viewer/doc-viewer.component.ts
I think this lib can also do the same thing https://github.com/laco0416/ng-dynamic
basically aslong as you're not wanting anything dynamically created then you're totally in the realm of what Angular can offer

@Toxicable What i see in doc-viewer component that pre rendered html is returned from server. We dont want to keep pre-rendered html on server, we want to get html template and render it in our component. How can i achieve this?

@asadmalik3 I don't understand what you mean by pre-rendered html?
The input documents are just normal html that you'd find on any html page.
Since you might misunderstand how this works I made a small demo of how it can be applied here
https://plnkr.co/edit/B5aIMZ7rYCLn1WizqUnW?p=preview

If there is something like {{title}} in my html returned from server, angular won't resolve it using your technique.

@asadmalik3 Nope, I never said it would.
Doing something like {{title}} requires the template to be compiled, I said

basically aslong as you're not wanting anything dynamically created then you're totally in the realm of what Angular can offer

Meaning that if you want to compile anything it wont work, it only works with preexisting components

You guys are funny, why do i ever choose angular if i have to serve static html from server? In my humble opinion you shouldn't be sharing this doc viewer example with anyone out there, as it is of no use. In any enterprise business application no one will "ever" have pre render templates (html) on server. Like page always gets rendered on different data for different client.

I have a strong feeling that moving forward you guys will have to offer some "easy" and "acceptable" way of getting templates from server and compiling them at run time. I don't want my application to be 100% super fast, i will be happy with 90% performance but it should provide me flexibility.

@Toxicable see this plunker https://embed.plnkr.co/jkWaZnfaH8bD7787BM5W/
I have list of products and list of clients. List of products is shown on top followed by list of clients.

One of my client wants to change the order, client wants to see list of clients first and then list of products. In that case i will happily ask client to modify html using web editor or something like it.

But right now, if i have to change order as i explained above, seems like i have to create a new component to achieve this.

So i will have 1 component showing products first and then clients and second component showing clients first and products second.

@asadmalik3 I see no reason why that needs to be dynamic at all. Asking the Client to edit the HTML?
just to change ordering? Why?
Just make a UI element (such as a select box) that changes the order and saves it to the DB, when they open it up again, load in this ordering selection and done.

This is not about changing order of data, this is about flexibility you provide to your clients. Think of those possibilities that arises when you allow your client to edit your page html. You are allowing them to do almost anything. What if one of our client wants to put an image advertisment on top of "Clients" section? and the other one wants to show some important information or instructions before products section? It is all in there, they can do whatever they want.

And on top of that every client wants to personalize their theme and wants to display data according to their need, some of our clients want boxed layout, and some wants to show data in tabular structure, some of our client wants to show image alongside every product etc. We won't sit down and make all these changes, we provide flexibility, client can do all these changes by themselves. Flexibility is the key here.

Do you mean something like in this article?
https://medium.com/@DenysVuika/dynamic-content-in-angular-2-3c85023d9c36

I read the article; the "Runtime compilation" is what I need. But as KarlXOL said, the solution is too complex and too heavy (compiled module need reference other third necessary modules etc.). It also didn't work well with AOT when I tested. "I personal need a straight and simple solution that we can dynamically set template of component in some way, but not break AOT behavoir". This is what I want.

BTW: I don't think "Dynamic content" is not only the content component already exist in module, app just reference and display it by user selection. But also the content component is unknown until run-time. It generate by user input or remote configurations.

+1

It would be nice to be able to provide a promise or an observable as template in the component decorator. Then we could have templates provided by the backend.

Hi,

we're currently also looking for some way to compile custom components at runtime. Our use case is to preview HTML email, that contains a lot of data that is edited using Angular 4 form.

Currently we use mustache templates that contain a full web page, and then we replace all the variables, place content in an iframe and update the iframe dimensions.

This works OK, but results in flickering as the whole iframe contents get's replaced again and again.

The HTML templates are selected by users from pre-existing selection (that are provided by a third party) or directly edited by the users, so we can't compile those using AOT.

I'm also interested in other solutions, and currently we're toying with idea that we would bypass Angular mostly and replace {{var_name}} with <span id="var_name"></span> and then using pure js to replace stuff.

This, on the other hand, forces us to implement what Angular was designed to solve, so it would be great to have and option to do it, even if it means that we would lose the ability to AOT.

Maybe this should be a separate project, so that we could code our apps using AOT, and then add @angular/dynamic-templates that would add the capability we're after, but let the remainder of the app work as AOT version. (At first it would be just JIT repackaged to be more user friendly, but given more effort could evolve to be something totally else)

What do you think?

Hi. I have a somewhat different usecase, but was advised that my feature request was a duplicate of this issue.

In my company we have an application that allows consumers to search for property data which are available through public national registers. If a user selects a property we will display a report with the available data. This report is generated by a third party and is pure html (just a big table). Some elements in the report contains "proto-links" to other pieces of information the user can purchase. These "proto links" are clearly marked/easialy selectable and contains all the information required to generate a link as attributes (basically unique identifiers to various documents). Our application currently supports 2 languages so JiT-compilation would take forever.

My current solution is to bind the sanitized html to the innerHtml of a component. During the AfterViewInit-phase the component traveses this html and replaces protolinks with anchor-elements. Things are working ok, I suppose (a bit hacky, but I'm fairly ok with that). It would however feel better (I can be a wee bit autistic about these things) if I could use routerLinks.
Navigation only occurs within the singlePage app and having page-refresh just because makes me a sad panda.

Ideally I suppose I would have a way to somehow declare a white-list of components and directives (like routerlink) that I could compile a bit of trusted html with. It would have to be possible to do this through AoT compilation. It feels like this should be possible through some we_advise_you_not_to_do_this_in_production-kinda way, but I haven't found a way yet.

This is not critical for my application atm (probably the only person who would register the difference is me) and I am super happy about the glorious framework that angular-2 has turned into:-).

@eliasre ... and what about to use the same principle as actually http://angular.io site where the pure HTML is also parsed somehow. During the process a dictionary of known components is lookup-ed up and on those places Angular native components are dynamically instantiated. So you can use any of them ... with all their inner functionality and so on ...

@mlc-mlapis that seems to be exactly 100% what I am looking for! I know this isn't stack overflow, but could you point me in the direction of some documentation on how to use this?

I feel like I am learning something brand new about angular 2 every day. Usually what I learn seems to be documented in the first 50 pages of the tour-of-heroes guide though :P

@Toxicable wow, looks cool. But is it works with content projection? I have markup like this (from backe-end) that should be dynamically added

<component1 smth="smth">
  <component2>item 1</component2>
  <component2>item 2</component2>
  <component3 smth="smth">
    <component4>smth</component4>
  </component3>
</component1>

and currently forced to use JiT (with aot on most code) to compile this in runtime

@artaommahe ... It is not possible directly for component1 ... but if you use a wrapper with a template like ^^^ ... but I never tried yet.

but if you use a wrapper with a template like

this makup is unknown until it came from back-end, there are hundreds of variations

@artaommahe ... ah, I see. But still with parsing and dynamic components instantiation it's possible to manage even your case ^^^ ... you just make an indirect content projection by another way ... via your own code, I think ...

@Toxicable, @artaommahe: Related to the "...stackblitz..." demo. This is old stuff and unusable for real life business applications. Too much code and overhead for inserting just normal html. The same for the dynamic component loader solution. In addition, inserting HTML without data-binding isn't the use case we are dealing with in daily life.

As it stands for now: There is no solution for loading the layout (HTML) for a component on the fly in angular 2-4.

@KarlXOL Im sorry you must misunderstand a few things about how that demo works.

This is old stuff

What makes something old bad?

Too much code and overhead for inserting just normal html

You only implement it once then you just HTML as normal, there is no overhead so I don't know what you mean by that. There are even npm packages that do it for you

real life business applications

well angular.io uses it so I don't know where you got that information from.

inserting HTML without data-binding

Data binding does work with this

As it stands for now: There is no solution for loading the layout (HTML) for a component on the fly in angular 2-4.

Yes there is

@Toxicable : No, it does not work with databinding. Update your demo with a {{myvar}} in your template and show me how it works. Thanks, in advance

@KarlXOL you cant interpolate directly into the HTML, that's never going to work without compiling the html, which isnt he point of the demo, you can databind in your components. The point is to show how you can have dynamic layouts and reuse your components in whatever way you want, by reusing the component you don't need anything recompiled.
What you're asking for is dynamically compiled templates which makes no sense in this context

@Toxicable so currently no way for my case except using JiT to compile markup with content projection in runtime? (i cant see any way to have hundreds of random makrups that can be changed any time to be precompiled)

@Toxicable Could you be kind and edit the demo to contain a textfield, that binds it's value to a variable named testname, and make the my-component component to use the value of testname as the name parameter value it displays. Basically I need to pass parameters to the dynamically created component and have it updated each time the value updates in the testname textfield.

I've tried dozens of different approaches but can't get it to work. If we can't get {{myvar}}in the html directly, we need a component called <display-value [value]="bind_to_var_name_x_or_y" />. Is this possible?

@swftvsn ... when you create a new instance of a component, you get its reference ... for example _cmpRef. Then through _cmpRef.instance you can access @Input() and @Output of that component like ... (@Input() myprop: string; and @Output() messages: EventEmitter<string> = new EventEmitter<string>();):

this._cmpRef.instance.myprop = 'xxx';

or

this._cmpRef.instance.messages.subscribe(this.messageSubscription);
...
messageSubscription = (_message: string) => {
     ...
}

Dynamic loading of HTML object should be the fundamental feature of Angular 2 but unfortunately, in the name of performance, it is not available. In future, this feature will come or not?

@Toxicable Thanks for your demo, Dynamic Event binding to the HTML object is not working e.g KeyPress, ngOnChanges to an input object

Thanks @mlc-mlapis for the input!

I've now explored the possibilities for a day and what I need to do probably can be done using dynamic components.

Two things that I have thought while chasing down the rabbit hole:

  1. The official documentation could be a bit better, I feel that it's not as good and detailed as the rest of Angular docs
  2. Even though most use cases can be accomplished using the current API I again feel that it could be a lot easier and more intuitive

The community is spoiled by using this awesome framework and thus we tend to expect everything to be easy and nice ;)

@swftvsn ... there is the official doc on the topic https://angular.io/guide/dynamic-component-loader. Of course, it could contain more examples, especially some very trivial one to allow a quick way how to catch the basic idea.

One question though - I have to make mustache templates live and I seem to be getting stuff like this:

<table>
  {{#each rows}}
    <tr>
      <td>{{someprop}}</td>
    </tr>
  {{/#each}}
</table>

I've already solved the dynamic component part, even when nesting stuff or loops, but I can't seem to find a good approach to solve this one, as I'm replasing the {{}} stuff with a component, but the component must NOT leave any trace of itself, as that really messes the table. Now that the replace=true does not work anymore, I'm a bit stumped on this one. Directive won't also work as there's nothing to attach it to.

Any ideas?

@mlc-mlapis I actually think that the official documentation caters for the simple case, but leaves the hard parts unanswered. Like digesting mustachio templates or other third party generated html and replacing parts of that with live Angular components.

I understand that speed is #1 and the rest comes after and the AOT nature of Angular makes many things hard. A good choice if you ask me, but the perfect world would still allow JIT (easily) side by side with AOT in the places devs see it fit.

@swftvsn ... for these cases attribute component is very suitable, like <tr mycolumns></tr> , where mycolumns is just a normal component with a template (for columns) or applying the same pattern also for <td mycolumn></td> ... but with dynamic component it is also unusable concept because you always create a trace ... nested element which is not allowed inside a table structure.

I am not sure but I think that the only chance is just to wrap the whole table as a dynamic component which can contain any sub-components, like <tr mycolumns></tr> repeated using *ngFor...

Dynamic templates are a requirement here too. We don't care about startup performance at all, since my application will be starting once every several days.

Dynamic templates add an extra extensibility layer to the application architecture.

Basically the idea is that with such extensibility we can regain lost flexibility. In pre-SPA days, we(as in web developers) would and could use backend tech will all the dependency injection and dynamic class loading/dynamic assembly loading to organize our application in an "everything is a plugin" concept. Frontend was just a part of it, and when we dynamically loaded some part of code that deals weith orders, that part of code would also supply a web frontend for its functionality.

With SPAs, we gained desktop-like performance and feel, but we lost that flexibility.

Using dynamic templates is paramount for thath kind of functionality. The browser-platform has all the flexibility needed for this and its very unfortunate thath features like AOT (which are important, but for other people) kind of cripple angulars potential.

Angular is going to release Angular Elements in a few weeks and I hope it will take care of this issue. Please check the below link for the Angular Elemetns.

https://docs.google.com/presentation/d/1jiXHYwfe1iSUiVLdKLFhSPRHLI_FmIvrI60QTpP6KLk/edit#slide=id.g26d86d3325_0_0

Angular is going to release Angular Elements in a few weeks and I hope it will take care of this issue. Please check the below link for the Angular Elemetns.

but this has nothing with random template assembling/compilation, how this solve that case when u have a dynamic UI and need to assemble this UI from random markup from backend? It cant be precompilated or created as component and changes very frequently

This feature is in their 2018 roadmap, I just got reply from Brad Green (@bradlygreen) in twitter. :)

@nsksaisaravana Can you share the link to the tweet?

@asadmalik3 Please check the below screenshot or browse https://twitter.com/bradlygreen and check the StackOverflow reports dramatic growth in Angular popularity tweet comments.

image

@nsksaisaravana @asadmalik3 is this feature (Dynamically load template for a component) is on the roadmap for 2018? do you have any link to 2018 roadmap where this is mentioned?

@sunilpes ... but it is available right now ... you only need to use Angular compiler, so you can combine AOT mode (usually for app core) + JIT mode (for those dynamic parts).

Read this: https://github.com/angular/angular/issues/20875

@mlc-mlapis I went through #20875 issue. I have tried loading modules on the fly (runtime) using compiler module using method compileModuleAndAllComponentsSync it works. But my question here is:
compiler module is internal to the Angular (low-level API). Is it going to work as expected in coming major versions as well?
We are trying to build our tool based on this module(compiler) to load dynamic modules on the fly.

@sunilpes ... but it is available right now ... you only need to use Angular compiler, so you can combine AOT mode (usually for app core) + JIT mode (for those dynamic parts).

cant use it due to this https://github.com/angular/angular/issues/19902 it's extremely slow for big templates

@sunilpes ... hmm, that's the question. Actually I think that version 6 will allow the same using as 5. There is a new view engine on the way .... code name ivy ... which will open really interesting new possibilities ... but it is about version 7 ... so too far to say anything concrete. 😄

Preview of Angular Ivy renderer- Angular's new view engine !!!

https://github.com/robwormald/ivy-code-size

image

Any updates on when this feature will be available?

@scottseeker ... you have to wait still for Ivy if current possibilities are not enough.

@mlc-mlapis we are awaiting for this feature. This feature has great potential to develop runtime pluggable modules. lets see how it goes ...

@KarlXOL If this still makes sense for you: create a v2Component with templateUrl = yourNewHTML... and extends your v1Component

@KarlXOL If this still makes sense for you: create a v2Component with templateUrl = yourNewHTML... and extends your v1Component

there are a lot of cases when markup comes from back-end (e.x. lesson content with many different exercises) and changes often via separate admin dashboard

I too would love this feature.
To be able to change the component "angular-html" at run time.

@mastronardif +1

I had a task where I needed to render arbitraty templates supplied from the server to display a custom form. Component had to be created and compiled at runtime to enable the bindings in the templates.

The steps to achieve that:

  • Create parent component that would create and render the dynamically compiled child component inside its ViewContainerRef.
  • Inject a compiler into it using Compiler token.
  • Use the Component and NgModule decorators (which are just functions under the hood) to define the component and the module that will declare it.
  • Compile both. This will give you the component factory that can be used to create the component instance.
  • Use the component factory to create the component inside the view container.
  • OPTIONAL: assign values to component inputs if it has any.
import {AfterViewInit, Compiler, CompilerFactory, Component, NgModule, ViewChild, ViewContainerRef} from '@angular/core';
import {CommonModule} from '@angular/common';
import {JitCompilerFactory} from '@angular/platform-browser-dynamic';

@Component({
    selector: 'app-parent',
    template: '<div #container></div>'
})
class ParentComponent implements AfterViewInit {
    @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef;
    constructor(private compiler: Compiler) {}

    ngAfterViewInit() {
        // Must clear cache.
        this.compiler.clearCache();

        // Define the component using Component decorator.
        const component = Component({
            template: '<div>This is the dynamic template</div>',
            styles: [':host {color: red}']
        })(class {});

        // Define the module using NgModule decorator.
        const module = NgModule({
            declarations: [component]
        })(class {});

        // Asynchronously (recommended) compile the module and the component.
        this.compiler.compileModuleAndAllComponentsAsync(module)
            .then(factories => {
                // Get the component factory.
                const componentFactory = factories.componentFactories[0];
                // Create the component and add to the view.
                const componentRef = this.container.createComponent(componentFactory);
            });
    }
}

Some things to keep in mind:

  • Remember to call clearCache on the compiler. If you don't, you will only be able to render your component once. When you try to compile it the second time Angular will complain about the same component existing in two different modules.
  • You don't have to use anonymous classes in component and module declarations. I actually used the class I already had in my application to declare the component.
  • The compiler is normally not available if the app was compiled with AOT compiler. To solve this we have to provide the compiler explicitly:
export function createCompiler(compilerFactory: CompilerFactory) {
    return compilerFactory.createCompiler();
}

@NgModule({
    imports: [
        CommonModule
    ],
    exports: [],
    providers: [
        // Compiler is not included in AOT-compiled bundle.
        // Must explicitly provide compiler to be able to compile templates at runtime.
        {provide: COMPILER_OPTIONS, useValue: {}, multi: true},
        {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
        {provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory]}    ],
    declarations: []
})
export class CoreModule {}

@alarm9k ... yep, this way to use JIT compiler and combine it with AOT core app is open and works ... we will see what dynamic things will be opened with Ivy ... even with superior performance.

@alarm9k I have very similar requirements and tried this same approach last year but could never get it to work. I think the thing I was missing was the changes to the module. So I'm trying it out real quick and the only thing I can't figure out from your code snippet is where this "createQuestionFunction" function comes from:

const componentFactory = this.createQuestionContent(factories.componentFactories[0]);

@BKHines Thanks for noticing that. I recklessly copy/pasted that from my app. Fixed.

@alarm9k haha, that's what I set it up as temporarily; I just didn't run it. I would have seen it work if I had just run it! Awesome stuff man! Thanks!

@alarm9k that's really interesting. Thank you! Do you have any stats for the cost of not having the compiler tree-shaken away from your bundle?

screenshot_20181103_224754

The difference is 329 kB.

The difference is 329 kB.

u missed gziping

@alarm9k Is it possible to inject services to component created like this? When i try to inject ChangeDetectorRef and ElementRef in component constructor, i keep getting Can't resolve all parameters for ComponentClass: (?, ?). thanks

Good day! Also faced with the need to replace the template in the current components from external data sources. Now, of course, I am trying to solve this problem through the dynamic creation of a component and an attempt to transfer the current logic to them. But it would be great to be able to change exactly the pattern. I'm really looking forward to this functionality. I would like an approximate assessment of the timing of the emergence of this functional. Thank.

@alarm9k That works really well, except on ng build --prod. No errors, but when I load the website, the console shows:

ERROR Error: "Runtime compiler is not loaded"
Ni /main.f449713c3fb3867ad6bf.js:1:68849
compileModuleAndAllComponentsAsync /main.f449713c3fb3867ad6bf.js:1:69182
ngAfterViewInit /6.c40d8b2dc5100b1af302.js:1:560
Xs /main.f449713c3fb3867ad6bf.js:1:126416
Qs /main.f449713c3fb3867ad6bf.js:1:126176
Zs

@SamuelMarks This is most likely because you haven't provided the compiler in your module.

Where does it need to be included?

You mean in the imports: [] of the parent @NgModule? - Which module?

@SamuelMarks Have you included this code in your module? I had a similar error months ago when I couldn't get this to work and it wasn't until @alarm9k 's example that I figured out the compiler was not in runtime (despite the now obvious message in the error! lol )

export function createCompiler(compilerFactory: CompilerFactory) { return compilerFactory.createCompiler(); }

@SamuelMarks You have to include compiler in the providers array of your module. Please see my code example above.

In Angular world "providing" means adding something to module's providers.

Any tips for capturing changes in the dynamic component from the parent component? I've got component A which has Property A on it. Component A creates the dynamic component, Component B from a string of HTML returned from an HTTP call. Inside of Component B is a bunch of Component Cs which are established components inside the project. One of the input properties on Component C is Property A. I can pass the value of PropertyA to Component C by putting it on the instance of ComponentB:

componentB.instance.propertya = this.propertya;

Then Component C shows the correct value when initialized. However, when I change Property A on Component A, it doesn't reflect on Component C. I moved Property A to a common service and that works fine (so I could stick with that), but I'm curious as to how to you can make this property change in the dynamic component and in the components in the dynamic component? I tried creating an input/output variable and subscribing to the output event, but no dice there either. Also tried below when a button is clicked to change Property A. Same results.

componentB.changeDetectionRef.detectChanges();

Here's a simple GitHub repo in case that didn't make any sense: https://github.com/BKHines/dynamiccomponentexample

@alarm9k @BKHines thanks, almost got it working:

Uncaught (in promise): Error: Loading chunk root-root-module failed.

import { Compiler, CompilerFactory, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';

import { ThisComponent } from './this.component';
import { theseRoutes } from './these.routes';

export function createCompiler(compilerFactory: CompilerFactory): Compiler {
  return compilerFactory.createCompiler();
}

@NgModule({
  declarations: [ThisComponent],
  imports: [
    CommonModule, RouterModule, RouterModule.forChild(theseRoutes)
  ],
  providers: [{ provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] }]
})
export class ThisModule {}

The example above provided by @alarm9k does not work in Angular 8 when using Ivy.

I get the following error:

ERROR Error: Uncaught (in promise): TypeError: Services.createRootView is not a function
TypeError: Services.createRootView is not a function
at ComponentFactory_.push../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.ComponentFactory_.create (core.js:18750)
at ViewContainerRef_.createComponent (core.js:16282)
at parent.component.ts:35
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
at Object.onInvoke (core.js:24359)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:390)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:150)
at zone.js:910
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:24350)
at resolvePromise (zone.js:852)
at zone.js:917
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:24350)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at drainMicroTaskQueue (zone.js:601)

@Igneous01 what version of Angular are you testing against?

@Igneous01 @petebacondarwin i got the same error, when enableIvy: true.

Project was generated with Angular CLI 8.1.3:

Angular CLI: 8.1.3
Node: 10.15.0
OS: win32 x64
Angular: 8.1.3
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.801.3
@angular-devkit/build-angular     0.801.3
@angular-devkit/build-optimizer   0.801.3
@angular-devkit/build-webpack     0.801.3
@angular-devkit/core              8.1.3
@angular-devkit/schematics        8.1.3
@ngtools/webpack                  8.1.3
@schematics/angular               8.1.3
@schematics/update                0.801.3
rxjs                              6.4.0
typescript                        3.4.5
webpack                           4.35.2

Package JSON file:

"dependencies": {
    "@angular/animations": "~8.1.1",
    "@angular/common": "~8.1.1",
    "@angular/compiler": "~8.1.1",
    "@angular/core": "~8.1.1",
    "@angular/forms": "~8.1.1",
    "@angular/platform-browser": "~8.1.1",
    "@angular/platform-browser-dynamic": "~8.1.1",
    "@angular/router": "~8.1.1",
    "bootstrap": "^4.3.1",
    "rxjs": "~6.4.0",
    "tslib": "^1.9.0",
    "zone.js": "~0.9.1"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.801.1",
    "@angular/cli": "~8.1.1",
    "@angular/compiler-cli": "~8.1.1",
    "@angular/language-service": "~8.1.1",
    "@types/node": "~8.9.4",
    "@types/jasmine": "~3.3.8",
    "@types/jasminewd2": "~2.0.3",
    "codelyzer": "^5.0.0",
    "jasmine-core": "~3.4.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~4.1.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~2.0.1",
    "karma-jasmine-html-reporter": "^1.4.0",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.15.0",
    "typescript": "~3.4.3"
  }

The error:

ERROR Error: Uncaught (in promise): TypeError: Services.createRootView is not a function
TypeError: Services.createRootView is not a function
    at ComponentFactory_.create (core.js:26827)
    at dynamic-loader.service.ts:92
    at ZoneDelegate.invoke (zone-evergreen.js:359)
    at Object.onInvoke (core.js:34209)
    at ZoneDelegate.invoke (zone-evergreen.js:358)
    at Zone.run (zone-evergreen.js:124)
    at zone-evergreen.js:855
    at ZoneDelegate.invokeTask (zone-evergreen.js:391)
    at Object.onInvokeTask (core.js:34190)
    at ZoneDelegate.invokeTask (zone-evergreen.js:390)
    at resolvePromise (zone-evergreen.js:797)
    at zone-evergreen.js:862
    at ZoneDelegate.invokeTask (zone-evergreen.js:391)
    at Object.onInvokeTask (core.js:34190)
    at ZoneDelegate.invokeTask (zone-evergreen.js:390)
    at Zone.runTask (zone-evergreen.js:168)
    at drainMicroTaskQueue (zone-evergreen.js:559)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:469)
    at invokeTask (zone-evergreen.js:1603)
    at HTMLButtonElement.globalZoneAwareCallback (zone-evergreen.js:1629)

@vunb - please note that you should only test IVY on the next versions of Angular. E.g. 9.0.0-next.0.

export function createCompiler(compilerFactory: CompilerFactory) {
return compilerFactory.createCompiler();
}

Thank you so much!

@alarm9k

First of all, thank you for the excellent solution you mentioned above. It has been extremely helpful to me thus far.

I'm having a bit of trouble implementing multiple components and routing between them when creating modules/components this way. Do you have any advice for implementing this?

For instance,

const myModule = NgModule({
            imports: [
                RouterModule.forChild([
                    {
                        path: "",
                        component: component1,
                        pathMatch: "full"
                    },
                    {
                        path: "component2",
                        component: component2,
                        pathMatch: "full"
                    }
                ])
            ],
            declarations: [component1, component2],
            exports: [component1, component2]
        })(class {});

Doesn't work. But excluding the imports makes it so that component1 loads by default.

If you need dynamic template, you are doing something wrong!

@djleonskennedy That’s a ridiculous statement that you didn’t even attempt to back up. If you don’t need the feature that’s fine, keep it moving.

I had a task where I needed to render arbitraty templates supplied from the server to display a custom form. Component had to be created and compiled at runtime to enable the bindings in the templates.

The steps to achieve that:

  • Create parent component that would create and render the dynamically compiled child component inside its ViewContainerRef.
  • Inject a compiler into it using Compiler token.
  • Use the Component and NgModule decorators (which are just functions under the hood) to define the component and the module that will declare it.
  • Compile both. This will give you the component factory that can be used to create the component instance.
  • Use the component factory to create the component inside the view container.
  • OPTIONAL: assign values to component inputs if it has any.
import {AfterViewInit, Compiler, CompilerFactory, Component, NgModule, ViewChild, ViewContainerRef} from '@angular/core';
import {CommonModule} from '@angular/common';
import {JitCompilerFactory} from '@angular/platform-browser-dynamic';

@Component({
    selector: 'app-parent',
    template: '<div #container></div>'
})
class ParentComponent implements AfterViewInit {
    @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef;
    constructor(private compiler: Compiler) {}

    ngAfterViewInit() {
        // Must clear cache.
        this.compiler.clearCache();

        // Define the component using Component decorator.
        const component = Component({
            template: '<div>This is the dynamic template</div>',
            styles: [':host {color: red}']
        })(class {});

        // Define the module using NgModule decorator.
        const module = NgModule({
            declarations: [component]
        })(class {});

        // Asynchronously (recommended) compile the module and the component.
        this.compiler.compileModuleAndAllComponentsAsync(module)
            .then(factories => {
                // Get the component factory.
                const componentFactory = factories.componentFactories[0];
                // Create the component and add to the view.
                const componentRef = this.container.createComponent(componentFactory);
            });
    }
}

Some things to keep in mind:

  • Remember to call clearCache on the compiler. If you don't, you will only be able to render your component once. When you try to compile it the second time Angular will complain about the same component existing in two different modules.
  • You don't have to use anonymous classes in component and module declarations. I actually used the class I already had in my application to declare the component.
  • The compiler is normally not available if the app was compiled with AOT compiler. To solve this we have to provide the compiler explicitly:
export function createCompiler(compilerFactory: CompilerFactory) {
    return compilerFactory.createCompiler();
}

@NgModule({
    imports: [
        CommonModule
    ],
    exports: [],
    providers: [
        // Compiler is not included in AOT-compiled bundle.
        // Must explicitly provide compiler to be able to compile templates at runtime.
        {provide: COMPILER_OPTIONS, useValue: {}, multi: true},
        {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
        {provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory]}    ],
    declarations: []
})
export class CoreModule {}

I have an issue with this solution, I am not able to add a service
image
image
image

and then I did ng serve --aot and I am getting this error, how can I inject the Data Service on a Runtime component?
image

@jalbatross @CharlesElGriego Guys, I am glad it helped someone (and sorry it didn't work for the others). I had a very narrow use case in that particular project for which I researched and found the solution. Almost immediately after that I switched to another project (I am a contractor), and I haven't used Angular for more than a year now (and I unfortunately don't have a spare half an hour to do some experimenting). So unfortunately, @jalbatross, I won't be able to offer you an Angular-related advice. However, I am a strong proponent of the idea that if something is extremely hard to do using a particular tool, there is a high chance that I may be using the wrong tool. By coincidence I had a similar task (arbitrary template compilation at runtime) in another project, but this time I avoided using Angular for the job. Instead I used React+JSX+Babel:

import * as Babel from '@babel/standalone';

const compiled = Babel.transform(
    '<div>Content</div>',
    {presets: ['react']}
).code;

If your templates absolutely need to be in Angular syntax, then I don't have any suggestion for you. However, if you are flexible about the format, you may consider, I don't know... the crazy idea of microfrontends and creating a small island of React (preact?) in the sea of Angular?

@CharlesElGriego Your images are not enough to understand. If you really want to seriously talk about it, create as simple as possible reproduction project on Github, which focuses only on the one problem and which is possible to clone and run.

@CharlesElGriego
Something you can do is pass in the service from the context where you are creating your component. Then assign that variable to the instance of your dynamically created component.

   // This is from the parent component
   constructor(private service1: service1) {

   } 
    ngAfterViewInit() {
        // Must clear cache.
        this.compiler.clearCache();

        // Define the component using Component decorator.
        const component = Component({
            template: '<div>This is the dynamic template</div>',
            styles: [':host {color: red}']
        })(class {
              // Makes service1 available in the created controller scope
              private dynamicAssignedService: service1;
              constructor() {
                console.log("Got service: ", dynamicAssignedService);
               }

             });

        // Define the module using NgModule decorator.
        const module = NgModule({
            declarations: [component]
        })(class {});



        // Services you need here 
        let sharedService = this.service1;

        // Asynchronously (recommended) compile the module and the component.
        this.compiler.compileModuleAndAllComponentsAsync(module)
            .then(factories => {
                // Get the component factory.
                const componentFactory = factories.componentFactories[0];
                // Create the component and add to the view.
                const componentRef = this.container.createComponent(componentFactory);

                // Assign the service to the component instance
                componentRef.instance.dynamicAssignedService = sharedService;
            });
    }
}

Hello! Thank you so much for your help @jalbatross and @alarm9k
I also created a repo based on your answers
https://github.com/CharlesElGriego/angular-aot-dynamic-components

@CharlesElGriego Thanks for that. I probably should have mentioned before but I've written an article about this case a while ago. There is also a link to the repo with the example.
https://www.linkedin.com/pulse/compiling-angular-templates-runtime-dima-slivin/

Hey @jalbatross, @CharlesElGriego , @alarm9k,

did you also manage to find a solution for using templateUrl rather than template?

I can't get it running using templateUrl, because angular can't load the markup. How can I enforce this programmatically?

ERROR Error: Uncaught (in promise): Error: Component 'Foobar' is not resolved:
 - templateUrl: ./foobar.component.html
Did you run and wait for 'resolveComponentResources()'?

Any help would be much appreciated!

Wait for Angular 9 (Ivy) which will be the real and best solution for solving this issue I had posted almost two years ago.
My issue is actually a request for "higher-order and dynamic" components which can be implemented now easily in Angular 9 (Ivy) - and which were also a no-brainer in AngularJS.

@knafteN To be honest, I doubt this is possible. I haven't looked at the Angular's code responsible for that, but I suspect that the template URLs are resolved at build time and the process itself is separate from the template compilation, thus having nothing to do with the compiler.

What kind of use case requires you to use template URLs to compile templates at runtime?

Thanks for your comments @KarlXOL and @alarm9k

I am looking for some mechanism which enables me to use different html templates for the same component. At the moment I am using only one template with a switchCase statement, but this approach is rather ugly and bloats up the code unnecessarily.
I need this because I have two clients, who want their own styleguide and theming to be applied. The logic stays the same.

This behaviour is already (somehow) implemented in https://github.com/NativeScript/NativeScript. There you can have one component.ts file and multiple html template files (namely component.html and component.tns.html). This tns.html file is loaded via convention but I don't know where and how to create this behaviour myself in my angular project.
Reference: https://docs.nativescript.org/code-sharing/code-splitting

Wait for Angular 9 (Ivy) which will be the real and best solution for solving this issue I had posted almost two years ago.
My issue is actually a request for "higher-order and dynamic" components which can be implemented now easily in Angular 9 (Ivy) - and which were also a no-brainer in AngularJS.

Hi Do you have a documentation of how Angular 9 will handle this? Thanks

Hey @jalbatross, @CharlesElGriego , @alarm9k,

did you also manage to find a solution for using templateUrl rather than template?

I can't get it running using templateUrl, because angular can't load the markup. How can I enforce this programmatically?

ERROR Error: Uncaught (in promise): Error: Component 'Foobar' is not resolved:
 - templateUrl: ./foobar.component.html
Did you run and wait for 'resolveComponentResources()'?

Any help would be much appreciated!

I have the same issue with the css styles

@knafteN @CharlesElGriego You should think about this from the HOCs point of view (High Order Components), as @KarlXOL mentioned. Ivy comes with the possibility to create HOC (components that return new components) soon, which was not possible in the actual Angular API, or it was very complicated.

The idea that you take any HTML code and merge it with existing component type/instance doesn't have a sense in run-time. Remember that one of the main architecture principles is the ability to predict the behavior in run-time and guarantee application stability. Taking any HTML from somewhere outside, and using it without any controlled manner is just a blind experiment, may be usable in dev mode, but certainly not in a production environment.

Taking any HTML from somewhere outside, and using it without any controlled manner is just a blind experiment, may be usable in dev mode, but certainly not in a production environment

Are you saying that there are no valid use cases to compile arbitrary HTML at runtime? If that's what you mean, then... well, there are plenty of use cases for that. Most of them have something to do with the HTML templates created and submitted to your system by the user.

@alarm9k Yep, I know what you mean. And this the main problem in fact. You can design the interfaces in many ways; one of them is also to accept directly pushed HTML code from a user. You can do the same thing in a different way by a different interface, but with the same and safer result.

If you are talking about parsing arbitrary HTML, you have to also remember about compilation and bindings to other parts of code. And for it, you also need a compiler in run-time, and with it, we are back in the actual version of Angular.

HOCs work in a different way. It is API which allows you to do it dynamically in run-time, step by step, part by part and in a controlled way, so you don't need a compiler for it.

HOCs work in a different way. It is API which allows you to do it dynamically in run-time, step by step, part by part and in a controlled way, so you don't need a compiler for it.

So this is the new way of creating dynamic components? I need to get the CMS Html from a headless CMS manager

@CharlesElGriego The HOC API is not published yet. On the base of the new Ivy renderer, it is in a design phase, so it is not possible to exactly say how it'll work and all available possibilities. I just wanted to express, that it won't be by the way of only taking any HTML and pushing it into a component type/instance to change its UI.

So at the moment there is no possibility to achieve the following split, using only one .ts-file?

  • app.component.ts (if some condition -> use red otherwise use blue)
  • app.component.red.html
  • app.component.blue.html

It doesn't have to be on runtime, I just want the dynamic behaviour of code splitting.

@knafteN Probably it is for some extra cases because templateUrl accepts ternary operator, like:

templateUrl: config.type === 1 ? 'red.html' : 'blue.html',

but the condition has to be statically analyzed because of Angular compiler doesn't run any code during the compilation phase. But this doesn't solve the dynamic behavior, it's still statically evaluated during AOT process.

@mlc-mlapis thanks, your variant works, but using an expression rather than the constant breaks the IDE support for the html files, as vscode/webstorm cannot evaluate the templateUrl and cannot know which html file is used for the component :(

@knafteN Yep, this another type of a problem, not directly related to Angular itself, but still limiting from a dev point of view. The reason why it's there is the fact that this case is very rarely used, so it wasn't implemented yet into those editors. So now, the only realistic way how to use dynamic HTML templates in run-times is to inject JitCompiler into an AOT application and compile it dynamically, even that way is not recommended because of the performance and security reasons, and wait for new HOC API in Angular 9.x (because it won't be available in the first release of 9.0 for sure).

Is there any guidance from Angular team when/if this functionality ever coming back? While condescending comments (if you need this feature, then you don't know how to code) may make authors feel good - they don't really answer the question. We give the implementation users the ability to customize the pages - and now we don't have a feature that for years has been our competitive advantage!

I need this feature for a completely different and valid use case (IMHO). I am developing a product. My own developed framework creates forms on server side and the rendering is also done there (Or we can call it backend). That has several advantages for me which we may keep out of this discussion.

Now, on a page where a user wants to search say products and the business logic is that they can set different elements in search criteria based on their permissions in the system. i.e. one user may be able to filter by price range and the other not whereas the second user may be able to filter by "date added in system" and the first can not.

In this case, I want to load this search criteria form from my backend and bind its elements to a model. The same worked very well with Angular 1.x with which I developed back in 2012 or so. The directive template urls were http urls and the backend used to return the form based on logged in user's permissions. Now, it does not seem possible with Angular.
I also tried with React where again it is not possible. (I don't want to use babel/standalone for performance reasons in production).
I am surprised hitting such a dead end with both the currently most popular front end technologies.

Going back to AngularJS (1.x) seems so difficult to justify.

@harishrohaj There is the general trend to not patch HTML code directly (not only in Angular itself), because of the very limited possibility to test such scenarios (the app never knows what would be patched at all) and all those unpredictable dynamic things decrease the expected stability of such apps.

@mlc-mlapis I understand your point.
Actually, it has been a valid way/feature earlier (in AngularJS), so it is a bit difficult to think against that as a user.
But now I am thinking inline with the idea and I think I can solve the problem in my case by creating some component that can create a form from some information of elements needed in it and bind the elements to the models.

@harishrohaj Yep, I understand that switching from AngularJS to Angular, especially how the head is automatically seeing the analytical model, is not easy. I think that you are on the right way now. 👍

@mlc-mlapis - it's not just switching from AngularJS... this functionality was available until Angular 5, and then removed. And there may or may not be a "general trend to not patch HTML code directly" (I do not see such trend at all) - it is the functionality that most ISV products need and have today.

So the real question is whether this functionality is there in 9 (and not documented), whether it's coming back any time soon, or maybe somebody comes up with some CKEditor type plugin.

@virshu It's still here the same functionality as before. It means that you can still load JitCompiler inside AOT bundled application and then compile dynamically modules and HTML templates. And it's still not recommended with reasons described above.

Another thing in the game can be some new features in Ivy (still not available for production and implemented for internal using till this moment) and API, which allow using of HoC concept or more flexible dynamic creation of components, on which the Angular team is working.

@mlc-mlapis - today marks 3 years since this thread was started. And from the very beginning you try to change a very specific question (Is it possible to load templates dynamically) to opinion-based discussion (it's not recommended; it's bad practice; whatever).

Given your obviously incorrect statement ("It's still here the same functionality as before.") it is difficult to take your other comments at face value. So, if possible, leave it hopefully to members of Angular team to provide factual information

Děkuji :)

@virshu As initiator of this thread, I totally agree with you. Time flies :-)
I'm still hoping there is something in the upcoming ivy-releases that will provide a solution to us

@virshu Hm, what wrong or misleading I said? Your formulation was:

this functionality was available until Angular 5 and then removed

I only stated that It's still here the same functionality as before. It means that you can still load JitCompiler ... that means that it was not removed and it's here as before because the concept of AOT is here from the first moment when Angular 2 was born.

If you wanted to say that dynamic direct HTML patching was available in AngularJS, but it's not in Angular at all, then you were right, but it's another story then.

Me too.

On Thu, Mar 19, 2020 at 1:55 AM KarlXOL notifications@github.com wrote:

@virshu https://github.com/virshu As initiator of this thread, I
totally agree with you. Time flies :-)
I'm still hoping there is something in the upcoming ivy-releases that will
provide a solution to us


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/angular/angular/issues/15275#issuecomment-601002102,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAFMV7QNGXRPZZIHZSQSQ2TRIGXUJANCNFSM4DEFOTBA
.

+1

I've been attached to this thread for a long time, and even though I'd like to see a component with dynamic html, I'm not afraid to change my mind to be "more Angular". In an ideal case, I expect from this thread something like best practice for situations where using dynamic html would be easiest way.

Let's imagine an example (a little more extensive example, not hello world for dynamic html, other users can add more details). :thinking:
_I create a stock exchange system where each currency tag (such as AUD), index (Dow Jones), exchange rate (EUR / USD), or a link to a user or article (@ user or # article_id) will cause these tags transform into Angular components with different functions. Articles would be edited by users themselves and stored in a database. The system should display the article loaded with all components._

Logically, the simple solution would be the components with dynamic content loaded from database.
Could someone from the Angular Team (_sorry, this would be beyond my possibilities_) write an article on an Angular blog (since no article has been published for a long time), how to achieve this solution using current Angular and dynamic templates (_something like the best but not recommended approach_), then why such a solution is wrong (I expect something like bad testing, worse efficiency...) and how do we can change (the design of?) an application to be in accordance with the Angular design (if it is recommended to display such an app using Angular).

Ideal result from watching this thread (since, as mentioned here, Angular has always made this possible) would be for me an example of how this can be done dynamically (wrong way), and how it should be coded right, according to the Angular approach. I think that this could be an interesting topic for the Angular Team on blog, and such an article could have a fairly positive response (at least teach everyone here how to do it right). If this article sufficiently described how to do this, perhaps this thread could be closed :smile: (I know, this is a bold statement).

With angular from version 2 on enterprise project, there were 0 use cases for feature like “dynamic template loading” Close this issue finally

With angular from version 2 on enterprise project, there were 0 use cases for feature like “dynamic template loading” Close this issue finally

Hi, I think you are wrong... On previous comments I added a "solution" for this, I know is not the best one but I had to take that approach because right now there's no way to implement a Headless CMS using Angular... My template HTML is coming from a CMS (Umbraco)

@CharlesElGriego what is your solution? can you explain your plan and we can make an PR together?

@CharlesElGriego what is your solution? can you explain your plan and we can make an PR together?

Oh no PR, it's not a core solution ... It's a solution with the Jit Compiler, it's the only thing I could find for my needs. But I'm still looking a solution using aot and that I can use for a Headless CMS

https://github.com/CharlesElGriego/angular-aot-dynamic-components

@CharlesElGriego solution for your case, is implement builder for you Headless CMS data structure, by using angular components, component should not have dynamic template, cause it will be inconsistent behavior for component!
@all would be better start programming, instead of dislike posts which are focused against this feature

Gee, @djleonskennedy - the dislikes are due to your repeated attempts to turn a clear and practical question into pointless opinion-based discussion! Please get a clue. Если 14 человек говорят что ты пьян, надо идти спать!

@virshu стяни лицо пожалуйста

Please, gentlemen, such answers will not take us forward. I see we're not going to move without a response from the Angular core team. I apologize in advance if I get someone involved in a conversation that doesn't concern them, but I think that @kara could give us advice focusing on the IVY part, @maxkoretskyi and @shmool have interesting presentations about the dynamic parts in angular and @bradlygreen said (in post from 2018) that dynamic templates is also one of the benefits of IVY.

I will try to summarize this discussion in a simplified way if you could comment this thread (with respect to your duties on ng-conf).

  • we would like to use a dynamic template (retrieved from a database that can be edited by app users) for components in angular applications
  • if I'm not wrong, the current options are adding a compiler (and maybe wrap angular elements to another app) - this is a bit clumsy solution, but there is no official example,
  • can you tell us what is the recommended / correct approach if we need to achieve a dynamically created template with IVY?
  • if this is not possible, how should we modify the design of such an application to match the angular approach?

An article on this topic on angular blog would certainly be a great idea. (With example how to do this correctly using IVY, and/or how to modify our apps to make it better in terms of app design to avoid such a requirement, if you believe that this approach is never justified.)

Thank you very much in advance for your reply

Hi all, Michiel pointed me to this interesting article about IVY HOC by Manfred. There is a bonus part at the end of this article called "Compiling at runtime". I don't have much time now, but maybe someone could try to build a demo, if we can create complete functional component with this approach,

important parts of the code:

import '@angular/compiler';

@Component({ template: '' }) 
class HigherOrderComponent { [...] }

ɵcompileComponent(HigherOrderComponent, { template: '<b>Hello</b>' });

@mlc-mlapis will this work when 'ng build --prod' ? Also, I saw your example render the name once but couldn't get it to update it when changed from the input. Was there something I'm missing?

@atiris I love how you have presented the question. Rather than debate whether the implementation we want is correct or not, have the devs please show us the right way to solve the problem. Good for you and hopefully we'll see movement soon (depending on whether HOC is the answer or not).

@jqsjqs It's only a simple example about the internal API, that is not public yet, because of the actual backward compatibility. I don't have exact information about the schedule when this will be available as a public API and also in which exact form. Also, NgZone is not applied here, and that's why the view is not updated when you change the model. Only view -> model direction works.

If anyone is still unsure of what the "real world use case" would be on this, I've run into one, and need an answer:
I work for a company that creates a software that handles multiple tenants simultaneously on the same server. I have been given the requirement of making an angular component that can pull it's template from a http request. We need this because we allow our clients to customize views (reordering divs, changing displayed properties, etc.). The ability to load the template via request allows us the flexibility to create a default version, that is then overwritten by the 'themed' version if it exists.
Fully understand that the alternate version of the template could indeed break the application, and that is a known and accepted risk.

@Nixon-Joseph So you either need an API for that component (for example based on JSON) that allows a customer modify the default template behavior (the component internally supports this API) or you need to define a set of binded input properties (with advantages of separated change detections) or the projections based on \ and \ for separate parts of the template.

Your sentence Fully understand that the alternate version of the template could indeed break the application, and that is a known and accepted risk. is probably the key misunderstanding in comparison to the Angular core team architectural point of view. Simply it's not acceptable from their side to introduce anything that can't be seriously guaranteed from the performance/stability/testing point of view. Even if you declare that it is an acceptable risk from your side, it doesn't affect the final decision.

@Nixon-Joseph - you might be interested to look at the approach we took in the application that powers angular.io. Each page of content is dynamically loaded (via HTTP) and instantiated into the DOM, with the use of Angular Elements to allow certain dynamic behaviours to be included in what is otherwise static content. See https://github.com/angular/angular/blob/master/aio/src/app/layout/doc-viewer/doc-viewer.component.ts#L131-L153

@mlc-mlapis I appreciate your response.
@pedroclayman this looks interesting, does it allow for angular to then interact with the dynamic content as if it were part of a component? Essentially, I'm needing to render a fully functional interactive component. I've looked at what you provided, and it seems promising, but I don't see anything obvious (at least to me) that specifically points to what we need.

I actually found a solution that works for us, the only downside is we have to disable AoT compilation for that project.
For those that come in after me wanting the same thing - Here's a quick overview of what I ended up doing.
First off, found the base for my solution here: https://stackblitz.com/edit/mlc-app-init-zyns9l?file=app%2Fapp.component.ts which I threw into a shared helper:

import { Component, NgModule, Compiler, ViewContainerRef, Type } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { SharedModule } from '../modules/shared.module';

export class DynamicComponentHelper {
    public static addComponent<ViewModelType = any>(compiler: Compiler, container: ViewContainerRef, template: string, viewModel?: ViewModelType, components: Array<Type<any>> = []): void {
        @Component({ template: template })
        class DynamicComponent {
            public vm: ViewModelType = viewModel;

            constructor() { }
        }
        components.push(DynamicComponent);
        @NgModule({
            imports: [BrowserModule, SharedModule],
            declarations: components
        })
        class DynamicComponentModule { }

        const mod = compiler.compileModuleAndAllComponentsSync(DynamicComponentModule);
        const factory = mod.componentFactories.find((comp) =>
            comp.componentType === DynamicComponent
        );
        const component = container.createComponent(factory);
    }
}

I then have a component calling it like so...

export interface VM { text: string; }

@Component({
    selector: 'app-component',
    template: `<ng-template #dynamicComponent></ng-template>`
    ...
})
export class VariationsComponent implements OnInit, AfterViewInit {
    @ViewChild('dynamicComponent', { read: ViewContainerRef }) _container: ViewContainerRef;

    private vm: VariationsComponentVM = { text: 'Hello World' }

    private viewInitialized: boolean = false;
    private componentTemplate: string;

    constructor(private compiler: Compiler) { }

    ngAfterViewInit(): void {
        this.viewInitialized = true;
        this.setUpDynamicComponent();
    }
    ngOnInit(): void {
        this.httpService.getComponentTemplate().subscribe(template => {
            this.componentTemplate = template;
            this.setUpDynamicComponent();
        });
    }

    private setUpDynamicComponent(): void {
        if (this.viewInitialized === true && this.componentTemplate) {
            DynamicComponentHelper.addComponent(this.compiler, this._container, this.componentTemplate, this.vm, [NestedComponent]);
        }
    }
}

And then the actual template being used could be as simple as...

<div>{{ vm.text }}</div>
<app-nested [input]="vm.text"></app-nested>

The great part about this, is all the built in angular templating stuff works, all the directives and everything. Once again, the only downside, is you have to lose AoT. Would it be/is it possible to disable AoT at a component level? It would be nice if we could compile the majority of a project in AoT, but leave a defined one out.

Right now my build commands have to be:
ng build ProjectName --aot=false
and
ng build ProjectName --prod --aot=false --build-optimizer=false

@Nixon-Joseph Yep, it was my historical demo created a long time ago. Generally, you should be able to build your app in AOT mode as usual, and additionally, you have to inject JitCompiler (this theme is discussed in some Angular GitHub issues with demo code) and using it to dynamically compile ad-hoc templates. So finally you can have a combined solution of AOT + JIT together. It's still not ideal, even it's not recommended from the Angular core team, again because of the performance/security/stability reasons, but it's working. I also recommend investing in some extended possibilities of the customizable interface of components and not allow patching HTML code without any control. The JitCompiler is able to stop the use of some not valid templates from its principle, but still, it's the too vague way how to support any customers.

@mlc-mlapis thank you for your comments. I'd love to integrate what I see in that .render function with what we're doing. But I don't think I have a good enough grasp on when/how to proceed. My main goal would hopefully to be able to continue to use AoT, and load the dynamic component via retrieved template. In production mode, if I don't use AoT, the project (all files combined) is almost 2M, but with AoT, it's under 800K. If I attempt to AoT compile my solution, it throws errors on the @Component portion of addComponent.
Would it be possible for you to provide a quick example of what your proposed solution would look like? I'd be happy to pull this conversation away from this tread so that we don't bloat it unnecessarily.

@Nixon-Joseph Start with angular/angular-cli#17663, that is the actual problem with `buildOptimizer` in CLI, which still allows AOT compilation but without the completed tree-shaking optimization. The reproduction demo is https://github.com/jcgillespie/ng-dynamic-optimized-repro and it can help you with your concept, even without the build optimization in the actual latest version of Angular.

@Nixon-Joseph Start with angular/angular-cli#17663, that is the actual problem with `buildOptimizer` in CLI, which still allows AOT compilation but without the completed tree-shaking optimization. The reproduction demo is https://github.com/jcgillespie/ng-dynamic-optimized-repro and it can help you with your concept, even without the build optimization in the actual latest version of Angular.

@mlc-mlapis
That's the problem with angular right now. Each feature request triggers a never ending discussion of low and lower technical reasons why something can be done and more often can't be done.
Sorry about this emotional outbreak. But we developers are waiting for long awaited features (like this) which are coming to slow and more often are not coming.
Other features for example are improvements in lazy loading, .etc. Looks like angular is loosing ground compared to other platforms

I and probably many others would really appreciate a meaningful roadmap on angular features planned.
Thanks

If anyone is still unsure of what the "real world use case" would be on this, I've run into one, and need an answer:
I work for a company that creates a software that handles multiple tenants simultaneously on the same server. I have been given the requirement of making an angular component that can pull it's template from a http request. We need this because we allow our clients to customize views (reordering divs, changing displayed properties, etc.). The ability to load the template via request allows us the flexibility to create a default version, that is then overwritten by the 'themed' version if it exists.
Fully understand that the alternate version of the template could indeed break the application, and that is a known and accepted risk.

Hi, I have a solution on my GitHub, it works also with AOT :)
https://github.com/CharlesElGriego/angular-aot-dynamic-components

@KarlXOL I understand you. But I also think that you're partially unfair in relation to the Angular as the whole. There are certainly some complicated parts that could be designed more nicely, but I also understand very well that breaking-changes in those areas are even more problematic and should be created with super high attention.

And there is also one of the principal Angular building stones, static analysis of the compiler that is in a direct position against dynamic anonymous patching of templates. All the time, many of us are thinking and looking for a clever solution that would satisfy both sides without serious and dangerous compromises.

@mlc-mlapis
Thanks for your answer. I really appreciate the time and brain you and your team is investing in angular to provide us a comprehensive, "feel-well" platform and environment. A great thank's for that!
But on the other hand over the last ~6 months I got the feeling that your team is struggling more with the complexity,dependencies, ... of angular, platform and tooling than being able to focus on thriving the platform forward.
The feature output for developers daily business need is slowing. Just to take Ivy as example which until now is just working behind the scenes and not has landed in the developers toolbox until now to improve application development in process or quality.

I bet on angular in the past and I'd like to do so in the future.

If anyone is still unsure of what the "real world use case" would be on this, I've run into one, and need an answer:
I work for a company that creates a software that handles multiple tenants simultaneously on the same server. I have been given the requirement of making an angular component that can pull it's template from a http request. We need this because we allow our clients to customize views (reordering divs, changing displayed properties, etc.). The ability to load the template via request allows us the flexibility to create a default version, that is then overwritten by the 'themed' version if it exists.
Fully understand that the alternate version of the template could indeed break the application, and that is a known and accepted risk.

Hi, I have a solution on my GitHub, it works also with AOT :)
https://github.com/CharlesElGriego/angular-aot-dynamic-components

@CharlesElGriego thanks for that! It looks promising, and super close to where I already was. I should be able to modify my solution to match more closely to yours and try it out pretty quickly. I see you have one issue in the repo mentioning that it doesn't compile aot in production. I'll see what it does for me and proceed from there.

@KarlXOL @mlc-mlapis I can definitely see both of your points here, and I appreciate the discussion being made. I will say though, I'm more on @KarlXOL's side on this one. While I fully understand and respect the attempt to make Angular as safe and stable as possible, it wouldn't hurt to have features (like the one requested), and just put them a little out of the way, with documentation that suggests against use - listing all the good reasons here.
This would then cover both cases wouldn't it? Unless someone uses the feature, they've not lost any stability. But if they choose to use it, then they have to acknowledge that it is against recommendations.

Will this be documented? I want to create a client side for a wordpress like allowing users to put html on a page like a blog. But it would be fun to allow some model bindings. Is this solution good or hacky?
https://stackoverflow.com/questions/46576727/angular-compile-and-create-components-at-runtime

I think using angularjs would be easy. Im looking for client side rendering only to avoid server script injection.

For anyone interested I want to explain how I solved this issue in my projects. I had the exact same issue: HTML and CSS coming in from a web API, completely dynamic. You cannot use both AOT and buildOtimizer: true if you want to compile Angular Modules and Components at runtime since the build optimizer strips the compiler out of the source.

I went completely out of the Angular bubble since it seem there is not really any support planned for such dynamic usecases. I just implemented web components. Not Angular Elements or any other framework, just plain browser web components running everywhere. I receive the HTML and CSS together with some binding information. The web component is capable of opening up a new shadow DOM in order to isolate application and component styles. This way incoming CSS or HTML cannot break your app.

In the end I am where I wanted to be: AOT + build optimizer in Angular, dynamic HTML and CSS from a web API at runtime including data binding. All that without having to pack the entire Angular compiler into the runtime. And it's a lot faster as well because I just stripped 2mb of unneeded js from the runtime.

For anyone interested I want to explain how I solved this issue in my projects. I had the exact same issue: HTML and CSS coming in from a web API, completely dynamic. You cannot use both AOT and buildOtimizer: true if you want to compile Angular Modules and Components at runtime since the build optimizer strips the compiler out of the source.

I went completely out of the Angular bubble since it seem there is not really any support planned for such dynamic usecases. I just implemented web components. Not Angular Elements or any other framework, just plain browser web components running everywhere. I receive the HTML and CSS together with some binding information. The web component is capable of opening up a new shadow DOM in order to isolate application and component styles. This way incoming CSS or HTML cannot break your app.

In the end I am where I wanted to be: AOT + build optimizer in Angular, dynamic HTML and CSS from a web API at runtime including data binding. All that without having to pack the entire Angular compiler into the runtime. And it's a lot faster as well because I just stripped 2mb of unneeded js from the runtime.

Hi, Do you have any example of this? Thanks

Here you go! I currently don't have time to explain every detail so here's the short story:

init() and update() get called by Angular. The array of span tags are the "databound" texts. There is surely some template parsing going on outside of the component so I can just for-loop the values and put them into the spans, but with the following example you should get the basic idea. And don't forget to register the custom web component on window...

export class TemplateContentWebComp extends HTMLElement {

  private tplDiv: HTMLDivElement;
  private tplSpans: Array<HTMLSpanElement> = new Array<HTMLSpanElement>();

  public init(templateCss: string, templateHtml: string): void {
    const template: HTMLTemplateElement = document.createElement('template');

    const css: string = `<style>:host { flex: 1; display: flex; flex-direction: column; } .tpl { flex: 1; box-sizing: border-box; }${!String.isNullOrWhiteSpace(templateCss) ? (' ' + templateCss) : String.empty()}</style>`;
    const html: string = `<div class="tpl">${!String.isNullOrWhiteSpace(templateHtml) ? (' ' + templateHtml) : String.empty()}</div>`;

    template.innerHTML = `${css} ${html}`;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));

    this.tplDiv = this.shadowRoot.querySelector('div.tpl');

    const spans: NodeListOf<HTMLSpanElement> = this.shadowRoot.querySelectorAll(`span[data-var]`);

    if (spans != null && spans.length > 0) {
      spans.forEach(span => this.tplSpans.push(span));
    }
  }

  public update(isEditable: boolean, values: Array<string>): void {
    if (this.tplDiv != null) {
      if (isEditable) {
        this.tplDiv.removeAttribute('tpldisabled');
      } else {
        this.tplDiv.setAttribute('tpldisabled', '');
      }
    }

    for (let i = 0; i < this.tplSpans.length; i++) {
      this.tplSpans[i].innerHTML = values[i];
    }
  }
}

Reading this comment I think we can close this issue right here, too 😞

https://github.com/angular/angular-cli/issues/17663#issuecomment-705737272

Hi, I have been searching for a way to load multiple templates into 1 single component for quite a while. Thanks to the post of @alarm9k I was able to find a way to do this. Ofcourse that way is only temporarily as it is not possible to launch it in production mode since it requires the compiler.

So for months I have been looking around for a way to do this but in production mode.
This actually didn't help since I couldn't find anything else so as a last resort I asked it on StackOverflow added some bounties to the question and add last I got an answer that is able to do this perfectly.

Ofcourse if you want separate stylesheets you can just add the stylesheet to the html template after you loaded it in from the database and it will work just fine (probably not the best but it works). Please don't credit me for this answer as all credits goes to the one who answered my question ofcourse.

https://stackoverflow.com/questions/63998467/angular-multiple-templates-in-one-component-based-on-id-with-template-store

@BillyCottrell It also depends on what you know ahead-of-time. If you know all your templates ahead of time, you can always run a node script (or similar) to interpolate them all together. There's probably ways of doing this directly with ng, hacking around what little of webpack it exposes…

@SamuelMarks that is true, but this can be used when you request templates from a server since the innerHTML in the example will work async so you don't need to know the templates beforehand and even if you do you can still load them in beforehand making it only work faster since there is no need to request them from a server. It is even possible to combine it with a timer and switch template every so often. This is just an easy way to still load templates no matter what you know and you can refresh it afterwards if you want to so you can display a different template or perhaps a newer version of the template.

I mean you could easily create a templating service that has your pre-known templates. Add those templates to it and if you wanted you could either select one of the templates that are known or you add a new one from the server based on your needs.
The only thing one needs to do is to load in the service that has both the pre known templates as the self made templates from a server. Which is good if you can't load in a template from a server so you can fallback to one of the pre-known templates. So there is no need to hack around anymore.

Yeah the premade templates is the key here. If you know AOT then you can have some fun, like with the aforementioned https://github.com/SamuelMarks/ng-md-components (that let's you use markdown templates). Trivial to upgrade its dependencies and add support for multiple templates to combine together (assuming anyone cares; just indicate).

Was this page helpful?
0 / 5 - 0 ratings