9

How would I translate that from Aura to LWC?

<aura:iteration items="{!v.contacts}" var="contact">
   <div class="{!contact.isActive ? 'slds-tabs--path dimmed' : 'slds-tabs--path'}">...</div>
</aura:iteration>
  • 2
    looks like question is related to this one - Expression Functions within Lightning Web Components – Oleksandr Berehovskyi Feb 6 '19 at 9:50
  • 1
    No expression language in the template anymore, so the expression moves to the JavaScript file using the ES6 get. – Keith C Feb 6 '19 at 9:55
  • 3
    But defining CSS class names in JS code is very unclean. Decades ago I learned to separate UI from Controller logic. – Robert Sösemann Feb 6 '19 at 9:56
  • Actually, you can add the class via expression syntax but it is slightly different from Aura and VFP.... you would use it like class={expression} <== no quotation marks and no "!v." preface. – binaryLady Mar 28 '19 at 19:18
15

The documentation covers this explicitly:

To compute a value for a property, use a JavaScript getter. For example, to convert the name to all uppercase letters, use a getter function in the JavaScript class, not an expression in the template.

Getters are much more powerful than expressions because they’re JavaScript functions. Getters also enable unit testing, which reduces bugs and increases fun.

Your example code would look like this:

<!-- MyComponent.html -->

<div class={tabClass}>
// MyComponent.js

get tabClass() { 
  return this.active ? 'slds-tabs--path dimmed' : 'slds-tabs--path';
}

Your concerns about separating UI from controller logic do not apply here as this is not a "controller". That MVC pattern is an Aura-ism. This is the code which drives your component's functionality so it makes sense that your JS would know about class names.

Edit:

After you changed your question, I think the best way to do what you're trying to do is to have a custom "contact" component which when clicked, becomes active, and has an

@api active;

property, which you can call from the parent. In your comments below you say this is too much overhead, but this is the proper way to do this if you wish to manage the state of the contact. In your code example you are only toggling one class, but in a real world scenario there are many different things which you might want to change about a contact and having many expressions makes the code harder to read and harder to test.

For most list items the suggestion is to have an individual element for each list item like so:

<c-list>
  <c-list-item></c-list-item>
  <c-list-item></c-list-item>
  <c-list-item></c-list-item>
</c-list>
  • 1
    Can you point me to any Salesforce or general web component code (e.g. Github) where they do it like that for CSS classes? Or even a part of a documentation where they explicitly recommend this? MVC is not an Aura invention and still holds as pattern für UI. – Robert Sösemann Feb 6 '19 at 12:43
  • 2
    This also doesn't work if the condition is based on a value I pass in. Imagine that the CSS style a <li> in an iteration and the class is dependent on the current element. Can I pass in params to setters. – Robert Sösemann Feb 6 '19 at 12:49
  • I changed my code to better show the loop situation.. – Robert Sösemann Feb 6 '19 at 14:36
  • 5
    @RobertSösemann expressions is not currently allowed in LWC template (and will probably not for the foreseeable future). If you want to dynamically style each items in an iteration, the recommendation is to map over the items of the list and add a className property on each item. <template for:each={items} for:item="item"><div class={item.className}></div></template> – pmdartus Feb 7 '19 at 10:34
  • 1
    IMPORTANT TIP: Don't forget to cascade css to minimize complexity. Assign dynamic css to the outmost html element of your component only and control the rest of the inner elements via cascading css. For example to hide a div with id #divId in the case the component is in the error state, you would write a css like .error #divId {display:"none"} where "error" is a class dynamically assigned to the root element when the component is in the Error State. – alcoforado Oct 6 '19 at 0:14
4

I was at a LWC presentation last night, and I think this recipe might get you on the right track: https://github.com/trailheadapps/easy-spaces-lwc/blob/develop/es-space-mgmt/main/default/lwc/customerTile/customerTile.js

The parent List component creates child tiles - notice how the getter references the object and customer object that are passed in to set the alttext. That recipe also shows how selecting something in the parent component can change the css in the child if I understood it correctly.

Parent:

<li class="slds-item" key={record.Id}> 
<c-customer-tile 
customer={record} object={sobject} oncustomerselect={publishSelect}>
</c-customer-tile>
</li>

Child HTML:

<lightning-icon icon-name={icon} alternative-text={alttext}></lightning-icon>

JS

import { LightningElement, api, track } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
export default class CustomerTile extends NavigationMixin(LightningElement) {
    @api customer;
    @api object;
    @track navRef;
    get icon() {
        return 'standard:' + this.object.toLowerCase();
    }
    get alttext() {
        return (
            'Navigate to ' +
            this.object +
            ' record detail for ' +
            this.customer.name
        );
    }
  • 2
    Do I really have to create a sub component if I want to have a list item dependant class?! That is way to much overhead when migrating components :-( – Robert Sösemann Feb 6 '19 at 14:01
  • That I don't know - I would take a look at the sample galleries (trailhead.salesforce.com/sample-gallery) to see if there is one that matches your requirements. If not, I would hit up Zanye Turner on Twitter (zaynelt) - she's been cranking out some pretty deep in the weeds content this month so is probably the best person to ask right now – BritishBoyinDC Feb 6 '19 at 16:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.