Imperative View & Template Composition APIs #43120
Comments
Question: Isn't it possible to create a small public layer on top of the Ivy instruction set? |
Another question: We can already mix-and-match more dynamic templates by using Angular Elements(web components generated by angular). |
@IgorMinar Thanks for this proposal! It really looks good. // this is where the magic happens
return createView([
html("<div>some static html, that will be automatically serialized by the `createTemplate` call</div>"),
tempateText(`
<app-user [userId]="userId"><app-user>
<ul>
<li *nfFor="let pref of preferences>{{pref.name} - {{pref.value}}</li>
</ul>`)
} ) ;
} ])
] ) ; Where it uses the same context as the Adding support for "normal" templates will name the use of this API a lot simpler. I know using it will need to ship the full Ivy compiler to the client, but I would like to be able to make that trade-off. |
I think that's exactly what this is - it's an API to imperatively construct an Ivy template function, but which doesn't require you to have specific knowledge about how to call the actual template instructions.
I don't think so, because such components still need to be written statically, even if their instantiation is more dynamic. This proposal allows for very dynamic constructions of views, based on runtime data structures.
This is a cool idea, too. One of the concerns here is that it would require some notion of a template scope (what |
@alxhub Thanks for the quick answers! It is good to have this cleared out of the way.
This would be the same thing as it is for stand-alone(module-less) components, or am I looking from the wrong side? Those problems need to be solved anyway for truly dynamic components as far as I can see. |
Sort of. The problem is that this scope has to be defined at runtime instead of compile time. One of the challenges here is that Angular actually erases scope information for |
@SanderElias thanks for all the questions. I think @alxhub fielded all/most of them already. I just want to chime in on: tempateText(`
<app-user [userId]="userId"><app-user>
<ul>
<li *nfFor="let pref of preferences>{{pref.name} - {{pref.value}}</li>
</ul>`)
} ) ; Dynamic template creation out of templates is something that I'd really like to avoid - it would basically be just a glorified way of using the current JIT compiler in production, which has lots and lots of problems (critical security, performance, and maintenance issues). I have an RFC coming out today, exploring the possibility of eventually removing JIT compilation mode entirely from Angular. I should post it within the next few hours — please stay tuned. The goal of this proposal is to enable dynamic composition of views in a way that is performant and secure. Many of us would like to have the good old |
I added a new section to the issue above describing the trade offs of this proposal. |
@petebacondarwin kindly pointed out that my example TS code was not syntactically valid due to typos, misaligned braces, and most problematically the use of |
@IgorMinar the first snippet has a const named protected async renderDynamically() {
const myCustomView = await createMyCustomView('./myBlue.component',
{userName: 'Kahless', myRoutePath: ['my-route'], showDetails: true});
// appends the view
viewContainerRef.appendEmbeddedView(myCustomView);
}
async function createMyCustomView(blueComponentESModulePath: string, myContext: {[key: string]: any}) {
const blueComponent = (await import(blueComponentESModulePath)).default;
// this is where the magic happens
return createView(...);
} |
@jnizet thanks you so much for pointing this out! I think I updated the code with all of your suggestions. I expected the code to have some minor syntax flaws when I was typing it out in the github issue editor, but I see that the next time I do something like this I should instead create a stackblitz that compiles but doesn't run. |
I love this, it's basically what I always hoped Ivy would enable. However, I'm confused about how updates will work. I realize the syntax is nowhere close to final, but I'll use it as a reference for discussion. In the example, if you used plain JavaScript expressions ( If we do need to limit ourselves to using structural directives over plain expressions then it may be appropriate to provide some helper functions for the built-in stuff, so maybe instead of this:
You could do:
Of course, the community could build helper functions like that themselves. My main concern is that the way expressions restrict the ability to update a view may trip people up. Thanks for sharing this openly! I'm excited for all the things a more dynamic Angular could bring. |
@sg-gdarnell great points, thanks for bringing them up! The important thing to note is that the current design doesn't rely on reevaluating the This brings me to the second part of your suggestion, it absolutely makes sense to add native support for |
Awesome proposal! Thanks! (+ thanks for the hidden Star Trek reference) |
@manfredsteyer wow, that was fast! I thought that it would take longer for someone to connect the dots. #highFive err... #elbowBump |
@IgorMinar Thanks for the additions and the answers. After having seen enough examples of how Now a new question arises: // you can use javascript expressions instead of `NgIf` to conditionally add view "nodes":
(Math.random() > 0.5) && text(" and followed by another component"), That will put |
Description
While declarative templating is great for most cases, developers often need more flexibility to create UIs dynamically, using components and directives (often) not known at the time of writing the component that generates this UI. Common use cases include data driven UIs (including forms), A/B experiments, UIs generated via plugin systems, etc.
Angular currently enables dynamic view or template creation only with major drawbacks in two ways:
Via the JIT compiler, which can take any string and compile it on the fly within the browser. This approach compromises security of the application (there is a high risk of introducing XSS and compromising the overall security model of Angular) and also comes with a major performance penalty due to the runtime cost of the compilation, and payload size of the overhead of the compiler.
Via ViewContainerRef#createComponent and similar APIs, which don't offer enough flexibility to dynamically compose views out of a mixture of static HTML, HTML with dynamically created bindings, components, and directives.
Proposed solution
With Ivy rendering/compilation pipeline being the default and ViewEngine being removed in v13, we can finally start taking advantage of flexibility of Ivy without having to worry about compatibility with ViewEngine, this opens up new possibilities including the follow...
We could introduce a new set of APIs that are built specifically for dynamic view composition. A proper research needs to be conducted to determine the shape of the API, but we can use the following PLACEHOLDER APIs to demonstrate the functionality and serve as a foundation for discussion, brainstorming, and actual API design research...
Where the
templateRef
is generated dynamically as follows:How would this be implemented?
Functions
template
,component
,directive
,text
would be just higher level wrappers around the private Ivy instruction APIs.Risks & unresolve stuff
There is a lot that needs to be researched in this area to determine the complexity of the implementation and overall viability. The following is an incomplete list of unresolved questions / issues:
ViewContainerRef
APIs accept only TemplateRefs or Components and not views directly. Is this a problem?As a result of these, you can expect major revisions of the proposed solution. The goal of this effort and use-cases this functionality would support should however remain the same.
Are there any trade offs?
Of course, there are always some trade offs.
The main ones that come to my mind:
What's the goal of this issue?
The goal is to write down some of the ideas that have been made possible thanks to Ivy and start collecting early feedback that could be used as an input for future RFC.
Alternatives considered
Expose the Ivy instructions as a public API. This has a major drawback that these APIs are low level (not developer friendly) and not stable (it would be hard to evolve the rendering stack if these APIs were public).
The text was updated successfully, but these errors were encountered: