Lightning Components Attributes

Lightning Components attributes are used to:

  • Pass information from one component to another component.
  • Pass information from an app to a component.
  • Pass information from an url query string to an app.
  • Hold information that is dynamically changed (eg: through javascript) and which is dynamically referenced within an app or component.

This is, attributes can be defined within a component or within an app. The purpose of this post is seeing examples of the types of attributes that we can define and how can we pass them from one component to another. Passing attributes from an app to a component would work exactly in the same way. For more information on dynamically setting attributes in an app through the query string, take a look at this.

The sintaxis we use for defining attributes is:

<aura:attribute name="header" type="String" required="true"/>

Once defined, we can reference them all along the component or app using the expression {!v.header}, which will dynamically evaluate the value of the attribute. Why “v”? Because “v” represents the view, which is built by a set of attributes. Also, we will be able of reading and manipulating the attribute values through javascript.

The properties name and type are compulsory for an attribute. Optionally we can indicate a description, a default value and if the attribute is required.

An attribute can have the following types:

  • Primitives
  • sObjects
  • Collections: list, set, map
  • Custom Apex classes
  • Javascript Object
  • Aura.Component, Aura.Component[]: we will see these types in a specific post about facets

Let’s see examples of each of the possible types. For that I have created a container component which references a subcomponent. The container component will set the attributes in the subcomponent when it instantiates it. This is the subcomponent ( MySubcomponent.cmp) code:

<aura:component >
    <aura:attribute name="header" type="String" required="true"/>
    <aura:attribute name="numbers" type="Integer[]" description="This attribute holds an array of integers"/>
    <aura:attribute name="numbers2" type="List" description="This attribute holds an array of integers"/>
    <aura:attribute name="ratingsByProduct" type="Map"/>
    <aura:attribute name="myFavouriteAccount" type="Account"/>
    <aura:attribute name="myFavouriteInstance" type="MyFavouriteClass"/>
    <aura:attribute name="jsObject" type="Object"/>
    
    <div>
        <h1>{!v.header}</h1>
        <p>The selected numbers are:
            <aura:iteration var="num" items="{!v.numbers}">  
                {!num}
        </aura:iteration>
        </p>
        <p>The selected numbers2 are:
            <aura:iteration var="num2" items="{!v.numbers2}">  
                {!num2}
        </aura:iteration>
        </p>
        <div id="ratingsByProductContainer"></div>
        <p>And my favourite account is {!v.myFavouriteAccount.Name}</p>
        <p>My favourite var is {!v.myFavouriteInstance.MyVar}</p>
        <p>type: {!v.jsObject.type} - model: {!v.jsObject.model} - color: {!v.jsObject.color}</p>
    </div>
</aura:component>

As you can see in the subcomponent we define:

  • A String attribute called header which is required. We can directly evaluate its value and print it between h1 tags.
  • An Integer array attribute, which we can iterate using aura:iteration tag for rendering each of its values.
  • A List, which is going to contain numbers as well, but could contain other things. We don’t have to specify the List content type when defining the attribute. We will iterate over the List for rendering its values as well.
  • A Map which will hold ratings given per product, for a set of products. We don’t have to specify the Map key or value types when defining it. As far as I know we need some js for being able of rendering the Map elements into a div. We will see how to do it later.
  • An sObject, concretely an Account. We can directly access the account fields with the dot notation, as in Visualforce pages.
  • A Custom Class instance. We can access the instance properties if they are annotated with @auraenabled with the dot notation.
  • A Javascript Object. We can directly render its properties with the dot notation as well.

Let see how we can reference this component and fill its attributes looking at the code of the container component (MyContainer.cmp).

<aura:component implements="force:appHostable" controller="MyContainerController">
   <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
   <aura:attribute name="myFavouriteAccount" type="Account"/>
   <aura:attribute name="myFavouriteInstance" type="MyFavouriteClass"/>
   <aura:attribute name="jsObject" type="Object"/>
    
   <c:MySubcomponent header="Hello"
           numbers="[5,4,3,2,1]"
           numbers2="[10,9,8,7,6]"
           ratingsByProduct="{ z: 3, y: 7 }"
           myFavouriteAccount="{!v.myFavouriteAccount}"
           myFavouriteInstance="{!v.myFavouriteInstance}"
           jsObject="{!v.jsObject}"        
    />
</aura:component>

My container component implements force:appHostable in order I can embed it in the Salesforce1 navigation menu to do some tests. For filling the attributes:

  • We can define values inline for the String, Integer array, List of integers and Map, as you can see in the code. We can manipulate these values with js if needed, but this is the simplest way.
  • For passing in an Account and a Custom Class instance, we need some communication with the server (through js!). I will show how to do it, despite that is not the purpose of this post, in order we have the full examples.
  • For passing in a Javascript Object, we will have  to define it in javascript.

In the cases in which we cannot directly define the attribute value inline, we will need to define some aux attributes in order the js code can set them, as the js code that belongs to this container component does not see the attributes that are defined in the referenced component.

So, how do we retrieve the Account and a Custom Class instance from the server and set them into the aux attributes? And how do we create the Javascript Object and set it into the aux attribute? For that we define the next client side controller (MyContainerController.js):

({
    doInit: function(cmp){
        // Call the server controller for getting my favourite account and set it in the myFavouriteAccount aux attribute
        var bringAccountFromServer = cmp.get("c.getMyFavouriteAccount");
        
        bringAccountFromServer.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                cmp.set("v.myFavouriteAccount", response.getReturnValue());
            } else if (state === "ERROR") {
                alert('Error : ' + JSON.stringify(response.getError()));
            }
        });
        
        $A.enqueueAction(bringAccountFromServer);
        
        // Call the server controller for getting my favourite instance and set it in the myFavouriteInstance aux attribute
        var bringMyFavouriteInstanceFromServer = cmp.get("c.getMyFavouriteInstance");
        
        bringMyFavouriteInstanceFromServer.setCallback(this, function(response2){
            var state = response2.getState();
            if (state === "SUCCESS") {
                cmp.set("v.myFavouriteInstance", response2.getReturnValue());
            } else if (state === "ERROR") {
                alert('Error : ' + JSON.stringify(response2.getError()));
            }
        });
     
        $A.enqueueAction(bringMyFavouriteInstanceFromServer);
        
        // Set a js object in the jsObject aux attribute
        cmp.set("v.jsObject", {type:"Fiat", model:"500", color:"white"});
    }
})

The client side controller, on initialisation, communicates with the server side controller enqueueing actions, which are calls to the server side controller methods, and setting a callback which will set the responses of the actions into the aux attributes when they are ready.

On the other hand, it creates a Javascript Object and directly sets it into the aux attribute that was intended for that.

The code of the server side controller (MyContainerController.cls) is the next one:

public class MyContainerController
{
    @AuraEnabled
    public static Account getMyFavouriteAccount()
    {
        return [SELECT Name FROM Account LIMIT 1];
    }
    
    @AuraEnabled
    public static MyFavouriteClass getMyFavouriteInstance()
    {
       MyFavouriteClass myClass = new MyFavouriteClass();
       myClass.MyVar = 'I\'am awesome!';
       return myClass;
    }
}

As you can see, the methods that are going to be called by the client side controller are annotated with @auraenabled. The properties or methods of the classes that are going to be used in the component has to be annotated as well:

public class MyFavouriteClass
{
    @AuraEnabled
    public String MyVar {get; set;}
}

So, we have seen almost the whole code. Something is missing, remember that we said that in the subcomponent controller we need some js for being able of rendering the Map elements into a div? Let see how to do this. One of the possible solutions is to overwrite the afterRender function in order, when the DOM is rendered, we have some more elements to it. Take a look at MySubcomponentRenderer.js code:

({
    afterRender : function(cmp){
        
        this.superAfterRender();

        // Go through the map contained in ratingsByProduct attribute for printing its values in a div
        var ratingsByProduct = cmp.get("v.ratingsByProduct");
        
        var ratingsByProductContainer = document.getElementById('ratingsByProductContainer');
        for (var key in ratingsByProduct){
            ratingsByProductContainer.innerHTML +='key:'+ key + ' - value: '+ ratingsByProduct[key];
        }
    }
})

What we do with this js is to take the Map object (which should have been set by the container component when referencing the subcomponent), and iterate over its key – value pairs, rendering them with some formatting inside a div.

Take a look at what my container component renders in order to see the results of our attribute passing exercise!

Screen Shot 2016-05-02 at 11.07.53

Finally, there are some expressions that allow us to perform some logical operations and calculations within a component markup using attributes directly. You can take a look at them here.

Here you have the code of these examples in order you can take a look at them.

8 thoughts on “Lightning Components Attributes

Add yours

  1. Hi, thats really a good article, would you able to share an example on how to pass array of strings for e.g. I was trying to pass month names as string[] to salesforce controller and get the data back in the data table. Many Thanks.

    Like

    1. Hi, I am not sure if you want to load month names into a String[] attribute doing a server call? In that case you would need to define a String[] attribute. Then you will need to have an @auraenabled method that returns a List, call it from the client side controller, and just set it into the attribute (eg: component.set(‘v.months’, response.getReturnValue());)

      Does this solve your question?

      Like

  2. I am getting one issue while passing a boolean value in a variable inside a loop to a component. In the receiving component, while I am checking the value of that variable in its controller, it is just showing the variable name instead of true or False.::

    Here is example:-

    I am setting linktile as True or False in parent controller like:-
    fnBundle.setViewFlag(“tilesinfo[“+i+”].linktile”,tilesArr[i].Tile_linkTile);
    fnBundle.setVariable(“tilesinfo[“+i+”].linktile”,tilesArr[i].Tile_linkTile);

    Now, in the receiving component, i.e ALL_TILES, I am getting the value of linkTile as “linktile”.
    Can anyone help me out on that?

    Like

  3. I’ve reproduced what I think you are trying to do, and for me it’s working. Let me know if it’s not like that:

    <aura:component implements="force:appHostable" >
        <aura:attribute name="tilesinfo" type="Object[]"/>
        
        <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
        
    	<aura:iteration items="{!v.tilesinfo}" var="tileinfo">
            <c:ChildComponent tileinfo="{!tileinfo}"/>
        </aura:iteration>
    </aura:component>
    
    ({
    	doInit : function(component, event, helper) {
            var tilesinfo = [{"linktile":true},{"linktile":false}];
            component.set("v.tilesinfo", tilesinfo);
    	}
    })
    

    <aura:component >
        <aura:attribute name="tileinfo" type="Object"/>
        {!v.tileinfo.linktile}
    </aura:component>
    

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: