2

We are able to render multiple template with this approach

import { LightningElement } from 'lwc';
import templateOne from './templateOne.html';
import templateTwo from './templateTwo.html';

export default class MiscMultipleTemplates extends LightningElement {
    showTemplateOne = true;

    render() {
        return this.showTemplateOne ? templateOne : templateTwo;
    }

    switchTemplate() { 
        this.showTemplateOne = !this.showTemplateOne; 
    }
}

But this is not what we want to achieve. We want to show two or more templates in the main page. This is the structure of the component that we have: split-html-file-in-single-lwc-component-image-1

We tried using:
mainPage.js

render() {
    return sectionA + sectionB + sectionC;
}

it return error:

Uncaught (in promise) TypeError: Invalid template returned by the render() method on [object Object]. It must return an imported template (e.g.: `import html from "./O.html"`)

We also tried to call the html file from the mainPage by using this:
mainPage.html

<template>
    <c-section-a></c-section-a>
    <c-section-b></c-section-b>
    <c-section-c></c-section-c>
</template>

it return error:

Error mainPage No MODULE named markup://c:sectionA found : [markup://c:mainPage] 

How can we call the html file in single LWC component?
The reason we are doing this is to split the html code into smaller pieces and still can use existing logic in mainPage.js.
We already hit the Salesforce limit because of so many html element that rendered based on condition and popup modals in single html file:

Error mainPage Failed to save Lightning Component Resource [lwc/mainPage/mainPage.html] of Lightning Component Bundle [mainPage]. Error: Value too long for field: Source maximum length is:131072

1 Answer 1

6

To use multiple templates, you create more components. This is the design philosophy of the Web Components design in general. If you're running into limits, you need to create additional components to break your elements down in size.

As a simple example, let's say we have something like this:

<template lwc:if={condition1}>
  <div class="outer-wrapper">
    <div class="inner-wrapper">
      Hello World!
   </div>
 </div>
</template>
<template lwc:if={condition2}>
  <div class="outer-wrapper">
    <div class="inner-wrapper">
      Goodbye World!
   </div>
 </div>
</template>

This is contrived, as we could just put the message into a variable, but this can be as complicated as we want it to be.

To clean up the duplicated code, we could write a wrapper component:

<template>
  <div class="outer-wrapper">
    <div class="inner-wrapper">
      <slot></slot>
    </div>
  </div>
</template>

Now, we can use that wrapper in our main component:

<template lwc:if={condition1}>
  <c-wrapper>Hello World!</c-wrapper>
</template>
<template lwc:if={condition2}>
  <c-wrapper>Goodbye World!</c-wrapper>
</template>

Further, we don't even need the template, we can use conditionals on almost any type of element, so we can reduce it to just:

<c-wrapper lwc:if={condition1}>Hello World!</c-wrapper>
<c-wrapper lwc:if={condition2}>Goodbye World!</c-wrapper>

The 128kb (131,072 bytes) limit happens to be the maximum length of a database field, which is why each file is limited to 128kb, but in general, the design philosophy of components is to make reusable parts that you can then combine through composition.

You can make the main element do stuff by sending events from the child elements:

<c-wrapper oncustomevent={handleCustomEvent} lwc:if={condition1}>Hello World!</c-wrapper>
<c-wrapper oncustomevent={handleCustomEvent} lwc:if={condition2}>Goodbye World!</c-wrapper>

...

// Inside wrapper/wrapper.js
handleElementClick(event) {
  this.dispatchEvent(
    new CustomEvent(
      'customevent', { detail: { message: 'Calling the parent...' } }
    )
  );
}

...

// in mainPage.js
handleCustomEvent(event) {
  // event.target is the specific wrapper that fired the event

However, let's say that you want to share a method across components. You can do that with either a service component, or by exporting functions from mainPage.

// utils/utils.js
export function sayHello() {
  console.log('Hello World');
}

// wrapper/wrapper.js
import { sayHello } from 'c/utils';
sayHello();

Or, you can export methods from the mainPage:

// mainPage.js
export function sayHello() {
  console.log('Hello World');
}
export default class MainPage extends LightningElement {
  // To demonstrate the function is outside the main class
}

...

// wrapper/wrapper.js
import { sayHello } from 'c/mainPage';

If the mainPage component is meant to be a singleton, you can also just store a reference to it for later usage:

let mainPage;
export mainPage;

export default class MainPage extends LightningElement {
  constructor() { // In JS, constructors are aways called constructor
    super(); // Required
    mainPage = this;
  }
  @api doSomethingInteresting() {
    console.log('Well, maybe not that interesting...');
  }
}

Now, another component can use that reference:

import { mainPage } from 'c/mainPage';
export default class Wrapper extends LightningElement {
  handleMouseClick() {
    mainPage.doSomethingInteresting();
  }
}

Of course, what you're trying to do might be possible with just clever template manipulation, but realistically, the proper way to build components is generally through composition.

You must log in to answer this question.

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