Closed boris-petrov closed 2 years ago
personally I don't think glimmer componets should allow this.
This could be the sort of thing LifeCyclecomponent solves
Glimmer is intended to be the lightweight, covers the 95% of use cases
I wouldn't want added callbacks and LifeCycle hooks forced on everyone
Here's some context:
We allow users to write their own HBS templates which are used in different places. One such place is the browser's title for example. There, obviously, only text is accepted. So I need a mechanism to get from an HBS template to a string of text (of course by passing some context data to the HBS template). Right now I do that by creating a classic component, instantiating it, rendering it and getting the text (all in JavaScript). I want to do the same with a Glimmer component for performance reasons. Not possible right now I think.
@NullVoxPopuli He doesn't need callbacks or lifecycle hooks.
I'd like to dig into the use cases here so we can get more details, but it sounded like most of the use cases could be solved if {{#in-element}}
worked on elements that were not attached to the DOM. I'm not sure if it does, but I think it would, and this would allow the user to render whatever they wanted into a fragment without ever actually attaching it to the document, and then do what they wanted with the output.
I agree with @pzuraq, in-element
is the right fit here. Also, just to clarify, in-element
does work properly even when the target element is not in the DOM.
If talks about use cases, for example, I have wrote an addon with itemscontrol (like in wpf), where component (item container) should be created in code, in response to itemcollection changing. Now I have to create model of component and render it in template. I would like to create and initialize component in code and manage component lifecycle by myself.
I think after learning more about the Glimmer rendering cycle while implementing strict mode, I'm more confident that this is something we do not generally want to support or allow to be a common pattern. There is a lot of overhead that comes with multiple rendering roots, both actual overhead of booting up another VM and running it, and conceptual overhead of managing a render root manually and not using templates.
So if we do want to add this capability, we need to not only show that it could be useful to some use cases, but that it would be essential to those use cases. That is, there would be no other reasonable way to accomplish these use cases that to have the ability to render multiple roots in a single application, manually.
@ivp-dev I understand how your example works, but can you provide more of explanation about why you architected it the way you did? Why, for instance, could you not have used contextual components and the {{component}}
keyword instead? Why is programmatic creation essential here?
Thank you for the answer. ItemsControl the base class for all components which should take care about multiple child elements. We can pass items to the component as a collection and render it internally in template
<TabControl @itemsSource="{{array}}"/>
or declare and pass it as a content and render with yield.
<TabControl as |Tabs|>
<Tabs.Tab @header="Head">Some content</Tabs.Tab>
</TabControl >
I want to support both of these cases. In the first case I can wrap item in Model class and add some functionality (for example extend it with some properties, such as isSelected property or events) and render it with {{component}}. In the second case the component itself is the data passed as a child and I need to add it to the internal collection to support some features, for example to support selection or filtering. I solved it through the render-modifier. When the child component rendered I pass class instance of the child component to the internal collection of the itemscontrol and now I have an access to properties and can support selection or filtering. The problem that I would solve is that I need to support two different classes with the same features. Model class for itemsSource and Component class. Component could be used as data item. Model class will no need if I could create component manually.
I'm closing this due to inactivity. This doesn't mean that the idea presented here is invalid, but that, unfortunately, nobody has taken the effort to spearhead it and bring it to completion. Please feel free to advocate for it if you believe that this is still worth pursuing. Thanks!
I think this RFC solves the needs here? https://github.com/emberjs/rfcs/pull/813 ?
... for creation and rendering of such templates.
This is provoked from this Discord discussion.
The main point is as follows. I have the following code currently (Ember 3.15):
It dynamically creates a classic component, registers it, instantiates it and the instance is rendered on the page to extract some info from it.
In order to achieve the same result with a Glimmer component, the first part of the code could be translated like so:
However the other parts have no Glimmer counterparts. I would have expected at least
getOwner(this).factoryFor(componentName).create()
to work fine but it blows up withFailed to create an instance of 'component:some-component'. Most likely an improperly defined class or an invalid module export.
.Having a unified JavaScript API for component creation and rendering for any kind of component (classic, Glimmer, template-only Glimmer) would be nice. Not sure if it makes sense or is something Ember wants to invest in, but I just wanted to put this here so a discussion can be started.
CC @Gaurav0