glimmerjs / glimmer-experimental

A set of experimental high-level APIs built on Glimmer.js
https://glimmerjs.github.io/glimmer-experimental/
59 stars 26 forks source link

Way to access rendered component instance #45

Open lifeart opened 4 years ago

lifeart commented 4 years ago

wor web components usage and for inegration with different external APIS, it's will be grate to have official ability to access rendered glimmer app.

following examples:

import { renderComponent } from '@glimmerx/core';
// renderComponent(klass, opts) => Promise

is it possible to return component instance as resolved promise argument? or opts = { connected(instance) {} }

xcambar commented 4 years ago

I'd like to second this statement, especially as detailed here: https://github.com/glimmerjs/glimmer.js/pull/235#issuecomment-583875216

The absence of such API forces implementors to use unpleasing (to say the least) workarounds ;)

argarcia-ottersoft commented 2 years ago

any update on this? any workarounds?

lifeart commented 2 years ago

@argarcia-ottersoft workaround exists, you could pass service into component and inside it's contructor assign this to some service property.


class App extends Component {
   @service app;
   constructor() {
       super(...arguments);
       this.app.setComponent(this);
   }

}

class MyService {
   component = null;
   setComponent(value) {
     this.component = value;
   }
}

const appService = new MyService();

await renderComponent(App, { services: { app: appService } } )
appService.component === App instance
argarcia-ottersoft commented 2 years ago

awesome! thanks @lifeart

follow up question, is there any way to properly unload the component? I'm trying to do cleanup in web components disconnectedCallback method

lifeart commented 2 years ago

@argarcia-ottersoft there is issue for it - https://github.com/glimmerjs/glimmer-experimental/issues/123

But, I could assume that minimal unload logic should be like:

// app's hbs

class App extends Component {
   @tracked
   isAlive = true;
   async destroy() {
       this.isAlive = false;
       await new Promise((resolve) => setTimeout(resolve)); // need to wait for rerender
       // nested components should be destroyed here and all you need is cleanup services used for component
   }
}
{{#if this.isAlive}}
   ... app logic
{{/if}}
argarcia-ottersoft commented 2 years ago

@lifeart, any reason why a nested component in App's {{#if this.isAlive}}<ChildComponent />{{/if}} would not fire the willDestroy() hook after setting the App's isAlive property to false? The <ChildComponent /> does successfully get removed from the screen

argarcia-ottersoft commented 2 years ago

never mind, it was an error on my end. An exception was being thrown while looping through scheduledDestructors cause of a version mismatch of @glimmer/destroyable. glimmer-class-based-modifier depended on version 0.77.3 while glimmer.js depended on 0.77.6 so updating glimmer-class-based-modifier to 0.77.6 fixed issue.