2

I've started writing my first LWC component and I have a problem with conditionally rendering DOM elements. I want to render an element if an expression returns true and not just a property. According to the developer guide, this is not possible? I'm working with this guide: https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.create_conditional

Here is an example of what I'm trying to achieve:

<template for:each={hours} for:item="h">
    <template if:true={h!==12}>
        Work
    </template>
    <template if:true={h===12}>
        Tea time
    </template>
</template>

hours is an array containing primitives: 0 to 23. Each hour of the day is a "Work" hour except 12, which is "Tea time". This doesn't work. I tried passing a function too but that doesn't work as well. I can't even pass an expression such as hours[h]. The developer guide says I can pass a JS getter function but that won't help because I can't pass it a parameter.

How can I overcome this?

Thanks!

2 Answers 2

6
  1. You need array of objects.

  2. In each object, you can add a boolean which conveys the conditional rendering.

Pls check below example:

poc.html

<template>
    <template for:each={hoursMain} for:item="h">
        <template if:false={h.isHour12}>
            <div key={h.hour} class="slds-theme_success">Work</div>
        </template>
        <template if:true={h.isHour12}>
            <div key={h.hour} class="slds-theme_error">Tea Time</div>
        </template>
    </template>
</template>

poc.js

hours = [];
@track hoursMain = [];
connectedCallback() {
    for (let i = 0; i < 24; i++) this.hours.push(i);
    // create new array for getting booleans
    this.hoursMain = this.hours.map(hr => {
        return {
            hour: hr,
            isHour12: (hr === 12)
        };
    });
}

isHour12 will give you the required boolean inside iteration in HTML


This actually is better with components

In this case you can use getters and also the code will be clean, maintainable and scalable

parent.html:

<template>
    <template for:each={hours} for:item="h">
        <div key={h.hour}>
            <c-child hour={h}></c-child>
        </div>
    </template>
</template>

parent.js:

@track hours = [];
connectedCallback() {
    for (let i = 0; i < 24; i++) this.hours.push(i);
}

child.html:

<template>
    <template if:false={isHour12}>
        <div class="slds-theme_success">Work</div>
    </template>
    <template if:true={isHour12}>
        <div class="slds-theme_error">Tea Time</div>
    </template>
</template>

child.js:

export default class Child extends LightningElement {
    @api hour;
    get isHour12() {
        return this.hour === 12;
    }
}
2
  • This will work but it's such a weird way to do it. It will increase memory consumption but what I'm more afraid of is the data management. My example here was really simple but in real life, I'll have to keep that boolean array updated on every data change occurring on the app, bummer :-\
    – Shai
    Aug 13, 2019 at 8:01
  • added better approach in that case in answer Aug 13, 2019 at 8:09
0

You can either add an property like "isTeaTime" in your data and use that or you can create a child-row component (with respective public property for the current data row) or similiar as iteration item which will take over the logic for rendering

1
  • Thanks for the detailed example. It's basically breaking it to components. In other popular JS frameworks the solution is so much easier to develop :-\ hope they will add more options on future releases.
    – Shai
    Aug 13, 2019 at 8:45

You must log in to answer this question.

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