1

I have related objects with a one-to-many relationship.

For example:

Owner1 ---> Thing1
Owner1 ---> thing2
Owner2 ---> Thing3

I want to display data from these objects in a table something like this:

Thing1.name | Thing1.thing | Thing1.Owner.name
Thing2.name | Thing2.thing | Thing2.Owner.name
Thing3.name | Thing3.thing | Thing3.Owner.name

I have two data structures -

thingArray = [Thing1, Thing2, Thing3];
ownerMap = {owner1.id :{owner1}, owner2.id : {owner2}};

Component:

<aura:component>
    <aura:attribute name="thingArray" type="List"/>
    <aura:attribute name="ownerMap" type="Map" />
    <!-- practice using aura iteration body and template properties -->
    <aura:iteration items="{! v.thingArray}" var="thing">
        {! thing.name } | {! thing.thing }| {! v.ownerMap[thing.Owner.Id].name } <br/>
    </aura:iteration>
</aura:component>

Which produces error:

expecting a positive integer, found 'item' at column 10 of expression: ownerMap[item]

I've created an additional component which displays this data:

component mapReader.cmp:

<aura:component>
    <aura:handler name="change" value="{! v.bigMap }" action="{! c.setStuff }" />
    <aura:attribute name="bigMap" type="Map"/>
    <aura:attribute name="bigKey" type="String"/>
    <aura:attribute name="littleKey" type="String"/>
    <aura:attribute name="littleKey2" type="String"/>
    <aura:attribute name="littleKey3" type="String"/> 
    <aura:attribute name="displayValue" type="String"/>
    {! v.displayValue }
</aura:component>

Controller mapReader.js:

({
    setStuff : function(component, event, helper) {
        let bigMap = component.get('v.bigMap');
        let bigKey = component.get('v.bigKey');
        let littleKey = component.get('v.littleKey');
        let littleKey2 = component.get('v.littleKey2');
        let littleKey3 = component.get('v.littleKey3');
        //Set values depending on which keys are available
        let value;
        if(littleKey2){
            if(littleKey3){
                value = bigMap[bigKey][littleKey][littleKey2][littleKey3];
            }else{
                value = bigMap[bigKey][littleKey][littleKey2];
            }
        }else{
            value = bigMap[bigKey][littleKey];
        }
        component.set("v.displayValue", value);
    }
})

I then use it like this:

<aura:component>
    <aura:attribute name="thingArray" type="List"/>
    <aura:attribute name="ownerMap" type="Map" />
    <!-- practice using aura iteration body and template properties -->
    <aura:iteration items="{! v.thingArray}" var="thing">
        {! thing.name } | {! thing.thing }| <c:mapReader bigMap="{! v.ownerMap}" bigKey="{! thing.OwnerId }" /><br/>
    </aura:iteration>
</aura:component>

This works fine to display on initial render.

PROBLEM

I need to be able to update the list, change order - when the thingArray gets updated the child mapReader components don't seem to get created.

It seems like it should be a simple thing to read a value from an object/map - what is the easiest way of doing this?

I really want to keep the data structure (array + map) as is, because the above is a massive simplification of requirements and there all kinds of reasons why pushing them all into the same data structure is going to be a massive headache and require a load of extra code (for example, I need to retrieve two sets of similar data using completely different criteria on different objects, and retrieve related lists from parent objects).

Edit: also... ideally I don't really want to put the table into a separate component and trigger re-render/ re-render the entire component to re display the child component, because in fact I have two tables that need to be able to interact and various other data on the parent component.

1

I see this asked a lot. The Aura framework does not handle this syntax currently:

{!Object[propertyName].value}

What you will have to do is use another component / controller to perform this functionality like this answer Is there a way to access object properties in Lightning expressions

| improve this answer | |
  • I have actually created such a component - the problem is that this child component doesn't render when the array being iterated through is updated - so if I change the order of the items in the 'thingArray' - the display updates but the parts output by the child mapreader component disappears. – eaeaoo Jan 15 at 14:18
  • Can you edit your question to show the use of that component? – Bryan Anderson Jan 15 at 14:20
  • It's already on there - towards the bottom. – eaeaoo Jan 15 at 14:21
  • 1
    So the one thing I see, you are detecting a change on bigMap in your child component which is tied to the ownerMap on the parent component, but if you changing thingArray it will not detect a change because that is tied to the bigKey attribute in your child component – Bryan Anderson Jan 15 at 14:26
  • 1
    Yep - that was it - I added in an init handler and it works fine. Thanks! – eaeaoo Jan 16 at 9:22

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.