javascriptaureliaaurelia-templating

How to convert string to expression ( value ) in aurelia repeat for?


Array used in repeat for loop

let loopArr = ["item.name + ' /'+ item.DisplayName? item.DisplayName: item.otherDisplayName", 
                    "item.description + ' /'+ item.anotherDescription"]

Template

<div repeat.for = item of data">
    <div repeat.for = "row of loopArr">
        <span textcontent.bind="renderRow(row, item)></span>
    </div>
</div>

Component method

renderRow(row, item){
    return eval(row)
}

Actually I wanted to display like below in template

<div repeat.for = item of data">
    <div repeat.for = "row of loopArr">
        <span>${item.name + ' /'+ item.DisplayName? item.DisplayName: item.otherDisplayName} </span>
        <span>${item.description + ' /'+ item.anotherDescription} </span>
    </div>
</div>

Since I wanted to loop through dynamic loopArr, instead of using eval to convert from string to value, is there any better way to compute the value from string? Also, eval doesnt work for multiline statements, is there any other approach/way to handle the above problem?

How to convert string to value and display in aurelia template?

Any help would be appreciated!


Solution

  • I'm not sure why you're adding the logic in string format and using eval. You could directly add it to the template and display it:

    <div repeat.for="item of data">
      <span>${item.name + '/' + (item.DisplayName ? item.DisplayName: item.otherDisplayName)}</span>
      <span>${item.description + ' / '+ item.anotherDescription} </span>
    </div>
    

    Let's assume you have a list of custom string formats and you are importing them from another file. You could create an array of functions instead of array of strings. This is much better way of deferring the string creation than running eval

    displayTemplates = [
     item => item.name + '/' + (item.DisplayName ? item.DisplayName: item.otherDisplayName),
     item => item.description + '/'+ item.anotherDescription
    ] 
    

    and then in the template:

    <div repeat.for="item of data">
      <template repeat.for="func of displayTemplates">
          <span>${ func(item) }</span> <!-- call each func on item object -->
        </template>
    </div>
    

    Also, there is a logical error in your string format. + operator has higher precedence compared to the ternary operator.

    So,

    item.name + '/' + item.DisplayName ? item.DisplayName : item.otherDisplayName
    

    is actually evaluated as

    (item.name + '/' + item.DisplayName) ? item.DisplayName : item.otherDisplayName
    
    

    So, this expression will always evaluate to item.DisplayName because item.name + '/' + item.DisplayName will never be falsy.

    You need to add () around the ternary operation:

    item.name + '/' + (item.DisplayName ? item.DisplayName: item.otherDisplayName)
    // OR
    item.name + '/' + (item.DisplayName ?? item.otherDisplayName)