2

I am really excited that Salesforce introduced the dynamic component instantiation in LWC with Winter24, however, I am wondering how to use it with dynamic positioning and rendering. With my requirements, I cannot explicitly add lwc:component to the HTML markup a definitive number of times. As the number of the dynamic component instances and their positions are determined in the runtime. I have tried to construct lwc:component with document.createElement() and append it to the template DOM as follows:

assignConstructor(type, gridContainer) {
    MAPPING[type]().then(({ default: SelectedConstructor }) => {
        this.buttonCmp = SelectedConstructor;
        return this.appendToRoot(gridContainer);
    })
    .then((root) => {
        return this.appendToTemplate(root);
    })
    .then((root) => {
        console.log(`${root} added to the template`);
    })
    .catch((e) => {
        console.error('Error:',e);
    });
}


appendToRoot(root){
    return new Promise((resolve, reject)=>{
        try{
            const columnDiv = document.createElement("div");
            columnDiv.classList.add('slds-col');

            const lwcElement = document.createElement("lwc:component");
            lwcElement.setAttribute("lwc:is", this.buttonCmp);
            lwcElement.setAttribute("name", 'test');
            lwcElement.setAttribute("label", 'test');
            lwcElement.setAttribute("rendered", true);
            columnDiv.append(lwcElement);

            root.appendChild(columnDiv);
            resolve(root);
        }catch(e){
            reject(e);
        }
        
    });
}

appendToTemplate(root){
    return new Promise((resolve, reject)=>{
        if(root){
            this.template.appendChild(root)
            resolve(root);
        }else{
            reject('Nothing to append to template')
        }
    })
}

And it does append the lwc:component with the imported element but has some issues with compiling...

enter image description here

with the static declaration of lwc:component it works perfectly fine.

<template>
    <lwc:component
        lwc:is={buttonCmp}
        name="dymamic button"
        label="dynamic button"
        rendered=true
    ></lwc:component>
</template>

enter image description here

So, looking at how to append N-number of components in some specific order... Please advise.

1 Answer 1

1

Using setAttribute converts the parameter you pass in into a String. In this case, the constructor's source code.

Something like the following should work:

constructors = [];
async connectedCallback() {
  let ctor = await("c/dynamicComponent");
  this.constructors = [...Array(5).keys()].map((id)=>({ id, ctor });
}
<template lwc:if={constructors.length}>
  <template lwc:for={constructors} lwc:item="component">
    <lwc:component lwc:is={component.ctor} key={component.id}>
    </lwc:component>
  </template>
</template>
3
  • Thanks for the recommendation. I have realised that I cannot use document.createElement() in this case and have to iteratively add components in for each loop by explicitly declaring <lwc:component> with the corresponding constructor. I have used the example provided in the documentation that suggests using public getter/setter to create the necessary constructor instance.
    – Andrew
    Jan 30 at 11:10
  • What you recommend is a static approach but I need to be able to append the constructed component to the arbitrary element of the template DOM
    – Andrew
    Feb 2 at 14:38
  • @Andrew You might be able to get away with using a custom render function? Alternatively, you could theoretically wrap the lwc:component inside a wrapper and move that element, although the runtime might get angry with you if it tries to rerender.
    – sfdcfox
    Feb 2 at 17:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .