Dynamically constructing a URL in a LWC for:each section

html-template-directiveslightning-web-components

I need the value attribute for a <lightning-formatted-url> in a for:each section of a LWC template to include the base url + a property from the current item, and I cannot figure out how this should be done.

If I try this:

<lightning-formatted-url value="https://sanctionssearch.ofac.treas.gov/Details.aspx?id={res.entity_number}" label={res.source} target="_blank"></lightning-formatted-url>

Then {res.entity_number} comes through as actual text in the url – no merging of data (which makes sense, but is not the desired result)

If I try this, it throws the following error on deployment: Invalid HTML syntax: missing-whitespace-between-attributes.

<lightning-formatted-url value="https://sanctionssearch.ofac.treas.gov/Details.aspx?id="{res.entity_number} label={res.source} target="_blank"></lightning-formatted-url>

So how am I supposed to create this link? I would do it in the js controller vs the template, but since I'm in a for:each already, I dont understand how I can get the value for the current item in JS, since the magic is happening in the template.

Per this post it seems like I could create a custom component for the link, as expressions are not allowed in template markup. Is that the only way?

This idea says there is a fairly recent pilot for allowing expressions – would that potentially solve this?

Guidance is greatly appreciated. The LWC code is below.

TEMPLATE

<template>    
    <lightning-layout>
        <lightning-layout-item flexibility="auto" padding="around-small">
        <table class="slds-table slds-table_cell-buffer slds-table_bordered slds-table_fixed-layout" style="width:100%">
            <thead>
                <tr class="slds-line-height_reset">
                    <th scope="col">
                        <div class="slds-truncate .slds-size_4-of-12" title="Name">Name</div>
                    </th>
                    <th scope="col">
                        <div class="slds-truncate .slds-size_2-of-12" title="Score">Score</div>
                    </th>
                    <th scope="col">
                        <div class="slds-truncate .slds-size_4-of-12" title="Source">Source</div>
                    </th>
                    <th scope="col">
                        <div class="slds-truncate .slds-size_2-of-12" title="Id">Id</div>
                    </th>
                </tr>
            </thead>
            <tbody>
                <template lwc:if={fullresults.results}>
                <template for:each={fullresults.results} for:item="res">
                    <tr key={res.id} class="slds-hint-parent">
                        <th scope="row" data-label="Name">
                            <div class="slds-cell-wrap" title={res.name}>{res.name}</div>
                        </th>                    
                        <td data-label="Score">
                            <div class="slds-truncate" title={res.score}>{res.score}</div>
                        </td>
                        <td data-label="Source">
                            <div class="slds-truncate">
                                <p><lightning-formatted-url value="https://sanctionssearch.ofac.treas.gov/Details.aspx?id={res.entity_number}" label={res.source} target="_blank"></lightning-formatted-url></p>
                            </div> 
                        </td>
                        <td data-label="Id Number">
                            <div class="slds-truncate" title={res.id}>{res.id}</div>
                        </td>
                    </tr>
                </template>
                </template>
            </tbody>
        </table>
    </lightning-layout-item>
    </lightning-layout>
</template>

JS
import { LightningElement, api } from 'lwc';

export default class OFAC_ResultViewer extends LightningElement {
    _cleanresults = '';

    @api
    get fullresults(){
        return this._cleanresults;
    }
    set fullresults(value){
            this._cleanresults = JSON.parse(value);        
    }

    
}

Best Answer

Typically, you manipulate the data in the controller via JS, and then use it in your markup. Because the objects are using JSON, you can add properties even though they aren't in the original object definition. Here's a simple POC:

//Controller with basic payload:

import {LightningElement} from 'lwc';

export default class DcugDynamicLink extends LightningElement {

    payload = [{name: "Peter", id: "123"}, {name: "Gorav", id: "456"}];

    get dynamiclinks() {
        let linkswithrecords = [];
        this.payload.forEach(record => {
            //record is the loop variable
            record.linkurl = 'https://sanctionssearch.ofac.treas.gov/Details.aspx?id='+record.id;
            linkswithrecords.push(record);
        });

        return linkswithrecords;
    }

}

HTML


<template>
    <h1>Dynamic Links</h1>
    <lightning-layout multiple-rows="true" >
    <template for:each={dynamiclinks} for:item="res">
        <lightning-layout-item size="2" key={res.id} class="slds-hint-parent">
                <div class="slds-cell-wrap" title={res.name}>{res.name}</div>
        </lightning-layout-item>

        <lightning-layout-item size="10"  key={res.id} class="slds-hint-parent">
                <div class="slds-truncate">
                    <p><lightning-formatted-url value={res.linkurl} label={res.Name} target="_blank"></lightning-formatted-url></p>
                </div>
        </lightning-layout-item>

    </template>
    </lightning-layout>

</template>