Au-compose in ts

In html I can use

<au-compose component.bind="myComponent" my-prop.bind="myProp"></au-compose>

Is there a functionality in Au2 where I can use this in typescript? I would like to do something like this (component/properties are dynamic):

// Pseudocode
bind() {
    composer.compose({
        component: MyComponent, // provide component
        element: myHtmlElement, // provide html element
        container: myContainer, // provide di container
        model: {
            myProp: 'xy'
        }
    });
}

Depending on your exact nature of use case, there are at least the following two options.

  • Synthetic views: if you want to assemble a dynamic markup for some known/registered components.
  • Controller API: if you want to go more low-level an hydrate a given component directly.
1 Like

Hi @Sayan751

Thanks for your feedback. I think I’m still missing something. In Au 1 there was the CompositionEngine, where I could do the following:

class MyComponent {
    myParam: string;

    activate(model: any) {
       this.myParam = model.myParam;
    }
}

const compositionContext = {
  container: this.container,
  childContainer: childContainer,
  viewModel: MyComponent,
  model: {
      myParam: 'xy'
  },
  bindingContext: null,
  viewResources: this.modalBuilder.container.get(ViewResources),
  owningView: this.owningView,
  viewSlot: new ViewSlot(myDivElement, true),
  host: myDivElement
};

await this.compositionEngine.compose(compositionContext);

I would like to dynamically render a component with a binding context.

The controller api looks nice, but I can’t get it to provide parameters to the ViewModel. I’ve added a @bindable xy and I scope to your example, but it seems that I am doing something wrong:

Hi @elitastic! I have tweaked your example a bit and generated a custom element definition on the fly, and used that for the controller API. I have assumed that the binding context and template comes from a different source.

Here is the working example: discourse 5349 - StackBlitz

Thanks @Sayan751. My real use case is to create a modal service which renders any custom element.

I have also tweaked the example a bit to better demonstrate my goal. I have a custom element “MyCe”, this element should be rendered by ts code. The component should behave as it would be rendered in html (including lifecycles, bindables).

Currently, I “bind” the data by calling the “activate()” method of the component manually, this works. I would prefer if the bindables could be used like in “normal” custom elements.

@customElement({
  name: 'my-ce',
  template: 'value from model: ${xy}',
})
export class MyCe {
  @bindable
  xy: string;
}

Is this somehow possible?

If you had

class MyCe {
  @bindable a
  @bindable b
}

and a call like this

.open({
  component: MyCe,
  model: { a: 1, b: 2, c: 3 }
})

What would happen to the c property in the model? Do you just want to ignore it?

I think we aren’t able to map out all the expected behavior of such scenarios, trying to make it natural in some cases will also make it weird in some other cases.

Thanks for your feedback, @bigopon.

Yes, I would expect to have the c property ignored in that case. Just like it is when you do the same in html:

<my-ce a.bind="1" b.bind="2" c.bind="3"></my-ce>
class MyCe {
  @bindable a: string;
  @bindable b: string;
  c: string; // this property is also ignored in that case
}

I understand the argument that it would not be expected in other use cases. It’s fine for me, I can deal with it. Thank you guys!

Hi @elitastic! I find no issues with having an activate method for the modal elements. Somehow, I find that to be cleaner than the alternatives. Having said that, there is a way to make use of bindable properties. Here is a working example: discourse 5349 - with bindables - StackBlitz.

It assumes that there is an identity mapping between names of the bindable attributes and the properties in the model object; that is, model.xy maps to @bindable xy and so on.

This is great, thanks for your help!

1 Like