Attributes and Expressions

Learning Objectives

Understand the difference between a component definition and a component
instance, and create multiple instances of a component.

Create basic expressions to display changing and calculated values.

Create conditional expressions for dynamic output.

Component Attributes

To this point, while we’ve created a couple of components, and learned a fair bit about building
apps with them (at a high level), the code we’ve written isn’t doing much more than what
plain HTML does. That is, the two components we’ve created output the same static text,
no matter what we do. You could put a dozen of them on the same screen, and they’d
always say the same thing.

Boring.

To change that, we need to learn two things. First, we need to learn how to enable a component
to accept input when it’s created. That is, we need to set values on the component. We
do this using attributes.

(The second thing we need to learn is how to actually use these values to change a
component’s behavior and output. We’ll do that after we figure out attributes.)

Attributes on components are like instance variables in objects. They’re a way to save values
that change, and a way to name those value placeholders. For example, let’s say we
wanted to write a helloMessage component that
prints a custom message. We can envision adding a message attribute to this component to
customize its output. And then we can set that message when we add the component to our
app, like the following.

You’ll
want to add this to your org, because we’ll use it a few more times as we go. But if you
do it now you’ll get an error. Why is that? Because the helloMessage component doesn’t exist yet. Lightning components validates
your code as you write it. If you try to save code that it knows is invalid—for example,
referencing a non-existent component—you’ll get an error. So, let’s figure out how to
create helloMessage first.

You can set a component’s attributes when you create it, as we did in the preceding example. You
can also change them over the course of your component’s lifecycle, in response to
actions the user takes, or events that happen elsewhere, and so on. And you can of
course read and use attribute values in a number of different ways. We’ll look at those
when we get to expressions.

For the moment, let’s look at how you define attributes for a component. An attribute is defined
using an <aura:attribute> tag, which requires
values for the name and type attributes, and accepts these optional attributes: default, description, required.

Whoa, that’s a lot of different ways to use “attribute” in a sentence! It’s really easy to get
confused here, because we have three different concepts with similar names. Let’s be
specific.

A component attribute is the place where you can store a value. In the preceding
example, the helloMessage component has a
component attribute named message. Most of the
time we’re talking about component attributes.

You define a component attribute using the <aura:attribute> tag. We’ll see an example of that momentarily.
Let’s call these attribute definitions.

The <aura:attribute> tag itself takes attributes when
you use it! 😖 That is, when you define a component attribute using the
<aura:attribute> tag, you set attributes
on <aura:attribute> that specify the “shape”
of the component attribute you’re defining. 😡 Wait, let’s try again: add a
component attribute definition by setting attributes on the attribute’s definition.
😭 A component attribute’s attribute definition takes attributes?
😴

This is why writers 😱. Let’s try to solve this terminology problem with some code.
😄

The helloMessage component has one component attribute, and
that attribute is defined by setting the name and
type of the attribute. The name of the
attribute is message and, once we learn about
expressions, that’s how you’ll reference it. It still only outputs static text and HTML,
but we’re inching closer to something useful.

👍 ?

The other attribute we’ve used here is type, and we’ve set
it because it’s required in an attribute definition. It says that the message attribute contains a string, which makes sense.
We’ll talk more about attribute data types, and the other parts of attribute
definitions, but first let’s learn about expressions, and make helloMessage actually do something.

Expressions

Instead of getting lost in words again, let’s dive right into making helloMessage work as intended.

We’re outputting the contents of message using the
expression {!v.message}. That is, this expression
references the message attribute. The expression is
evaluated, and resolves to the text string that’s currently stored in message. And that’s what the expression outputs into
the body of the component.

Ummm…what the heck is an “expression”?

An expression is basically a formula, or a calculation, which you place
within expression delimiters (“{!” and
“}”). So, expressions look like the
following:

{!<expression>}

The formal definition of an expression is a bit intimidating, but let’s look at and then
unpack it: An expression is any set of literal values, variables, sub-expressions, or
operators that can be resolved to a single value.

Yep, basically a formula, much like you’d write in a calculation field, filter criteria,
or Visualforce. The formula, or expression, can contain a variety of things. Literal
values should be obvious; they’re things like the number 42, or the string “Hello”. Variables
are things like the message attribute. Operators
are things like +, -, and so on, and sub-expressions basically means you can use parenthesis
to group things together.

All we’ve done is move the “Hello” part from static text outside the expression to
literal text inside the expression. Notice that we’ve used the “+” operator to
concatenate the two strings together. This might seem like a pretty small difference,
but moving the greeting text inside the expression lets you use labels, instead of
literal text, which makes it easier to update (and translate) your components. For
example:

{!$Label.c.Greeting + v.message}

Did you notice what our formal definition of expressions left out? JavaScript function
calls. You can’t use JavaScript in expressions in Lightning Components markup.

One last thing about expressions before we move on. You can pass them to another
component to set the value on that component. Here’s a new component that passes in a
custom value to the helloMessage component. Passing
the value to the other component overrides the value on that
component.

Value Providers

Actually, we need to talk about another aspect of expressions. In the preceding examples,
we’ve referenced the helloMessage component’s
message attribute with v.message. What’s the
“v.” part?

v is something called a value provider.
Value providers are a way to group, encapsulate, and access related data. Value
providers are a complicated topic, so for now, think of v as an automatic variable that’s made available for you to use. In our
component, v is a value provider for the
view, which is the helloMessage
component itself.

v gives you a “hook” to access the component’s
message attribute, and it’s how you access
all of a component’s attributes.

Values in a value provider are accessed as named properties. To use a value, separate the
value provider and the property name with a dot (period). For example, v.message, as we’ve seen.

When an attribute of a component is an object or other structured data (that is, not a
primitive value), access the values on that attribute using the same dot notation. For
example, {!v.account.Id} accesses the Id field of
an account record. For deeply nested objects and attributes, continue adding dots to
traverse the structure and access the nested values.

Attribute Data Types

Accessing structured data is a nice segue back to talking about attributes, and specifically about non-primitive attribute types. message is a string, but there are a number of different attribute types.

This component has one attribute, expense, which is the
custom object we created waaaay back at the start of this module. The component’s
purpose is to display the details of an expense by referencing the field on the
Expense__c record, using the {!v.expense.fieldName} expression. We’re using the
<lightning:input> component of type="toggle", which is a checkbox in the form of a
toggle, so that we can update the value in the UI later.

Other Aspects of Attribute Definitions

When it comes to the attributes you set on the <aura:attribute> tag, here’s the rest of what you need to know.

The default attribute defines the default attribute value. It’s used when the attribute is referenced and you haven’t yet set the attribute’s value.

The required attribute defines whether the attribute is required. The default is false.

The description attribute defines a brief summary of the attribute and its usage.

Setting the default value for an attribute with a complex data type can be kind of tricky. We’ll see an example later, though, so for now we’ll just give you the heads up.

Fun with Attributes and Expressions

To illustrate a few more concepts about attributes and expressions, let’s create a really silly component, helloPlayground, with the following markup.

Now add the helloPlayground component to your harness app, and see how it runs!

There’s a number of new things here. We won’t go into depth on them right now, but you’ll see all of these again.

First, helloPlayground has one attribute, messages, that’s a complex data type, List. And
it has a default value for that list, an array of three single-quoted strings separated
by commas. And, in the List Items section, you can see how to access each of the strings
using an index.

What happens if someone creates a <c:helloPlayground> with only two messages? Accessing the third item will fail, and while it won’t cause a crash here, with more complex components it might.

So, in the List Iteration section, you can see a better way to work through all items in the list. The <aura:iteration> component repeats its body once per item in its items attribute, so the list shrinks or grows as we have fewer or more messages.

In the Conditional Expressions and Global Value Providers section, you can see a way to choose between two different possible outputs. The format is a bit awkward, because this is markup rather than, say, JavaScript, but the <aura:if> component lets you, for example, add an edit button to a page only if the user has edit privileges on the object.

Finally, something that is a little less obvious. In object-oriented programming,
there’s a difference between a class and an instance of that class.
Components have a similar concept. When you create a .cmp resource, you are providing
the definition (class) of that component. When you put a component tag in a .cmp,
you are creating a reference to (instance of) that component.

It shouldn't be surprising that we can add multiple instances of the same component with different attributes. In the preceding example, when you use the default value for messages, you’ll end up with eight references to (instances of) our <c:helloMessage> component. If you pass in a longer list, you could end up with (many) more. All from our one little component!