Scenario
In lightning, we have developed multiple components for different functionalities. All custom components include a lot of boilerplate code and we will have to exclude most of the redundant code by building generic function in the helper part of aura bundle. However, it wouldn’t be the perfect solution to avoid the redundancy as we will have to do the same for other components as well. For example, Communication between an apex controller and a component is written separately for each custom component, even if the components are related to each other. Are there any mechanisms available in lightning for abstracting the boilerplate into one component for others to make use of it?
From my experience, this can be solved by Inheritance as it makes the code more structured and flexible.
The Salesforce Apex framework supports inheritance similar to what we see in object-oriented programming languages like Java and others. Is Aura framework built to support inheritance?
Solution
Yes, Lightning supports extending components based on hierarchy. However, it is not similar to the traditional one. In lightning, everything is treated as a component and it is a bundle of Helper, Controller, CSS, Render and Design. Super component is the extendable component which has extensible =’true’ or abstract = ‘true’ attributes in the header. The subcomponent would have the following attribute in the header.
extends="namespace:component_name"
When a super component extends a subcomponent, it inherits all of the attributes and the helper method of the parent. The abstracted components can’t be used directly in the markup since it’s only partially implemented.
Example 1
Consider the following example.
BaseComponent.cmp, ChildComponent.cmp & TestApp.app
<aura:component extensible="true" abstract="true"> | |
<aura:attribute name="record" type="String" /> | |
In parent Component – Record: {!v.record} – {!v.body} | |
</aura:component> |
<aura:component extends="c:BaseComponent"> | |
<aura:set attribute="record" value="Record Value Set From Child Component " /> | |
Child Component | |
</aura:component> |
<aura:application > | |
<c:ChildComponent /> | |
</aura:application> |
The available attributes in the parent component are available in the child component to set and use. Here, the record attribute of the parent component is accessible in the child component to set the value using aura: set. You may have noticed that v.body is not defined in the parent and the child component as an attribute. The body attribute is inherited from the root component of aura and flows down to its decedent components. Normal attributes (like the record attribute in the BaseComponent ) are having the same value throughout the hierarchy but body attribute behaves differently in each level. Here, the body attribute holds the markup data of the child component.
The c: ChildComponent included in the TestApp shows the following output.
TestApp --- Output
In parent Component - Record: Record Value Set From Child Component - Child Component
You can see that the Child Component text in the child component markup is set to the body attribute of the parent component.
Example 2
<aura:component extensible="true" abstract="true"> | |
<aura:attribute name="record" type="String" /> | |
In parent Component – Record: {!v.record} – {!v.body} | |
</aura:component> |
<aura:application > | |
<c:BaseComponent /> | |
</aura:application> |
TestApp --- Output
The above example shows how an abstracted component behaves in a lightning application when it is declared directly. The abstracted component can be used only for extending to other components.
Conclusion
The redundancy issue can be solved easily by employing an abstracted or extensible component. With this, we can have the attributes and helper methods of parent component shared among all its child components. A child component can implement any number of parent interfaces but can’t extend more than a single parent component. The best practice is to modularize all the complex logic ( like server interactions ) into abstract components which then can be extended to other components.
Inherited Component Attributes
Attribute values are identical at any level of extension. There is an exception to this rule for the body attribute, which we'll look at more closely soon.
Let's start with a simple example. c:super has a description attribute with a value of "Default description",
<!--c:super-->
<aura:component extensible="true">
<aura:attribute name="description" type="String" default="Default description" />
<p>super.cmp description: {!v.description}</p>
{!v.body}
</aura:component>
Don’t worry about the {!v.body} expression for now. We’ll explain that when we talk about the body attribute.
c:sub extends c:super by setting extends="c:super" in its <aura:component> tag.
<!--c:sub-->
<aura:component extends="c:super">
<p>sub.cmp description: {!v.description}</p>
</aura:component
Note that sub.cmp has access to the inherited description attribute and it has the same value in sub.cmp and super.cmp.
Use <aura:set> in the markup of a sub component to set the value of an inherited attribute.
Inherited body Attribute
Every component inherits the body attribute from <aura:component>. The inheritance behavior of body is different than other attributes. It can have different values at each level of component extension to enable different output from each component in the inheritance chain. This will be clearer when we look at an example.
Any free markup that is not enclosed in another tag is assumed to be part of the body. It's equivalent to wrapping that free markup inside <aura:set attribute="body">.
The default renderer for a component iterates through its body attribute, renders everything, and passes the rendered data to its super component. The super component can output the data passed to it by including {!v.body} in its markup. If there is no super component, you've hit the root component and the data is inserted into document.body.
Let's look at a simple example to understand how the body attribute behaves at different levels of component extension. We have three components.
c:superBody is the super component. It inherently extends <aura:component>.
<!--c:superBody-->
<aura:component extensible="true">
Parent body: {!v.body}
</aura:component>
At this point, c:superBody doesn’t output anything for {!v.body} as it’s just a placeholder for data that will be passed in by a component that extends c:superBody.
c:subBody extends c:superBody by setting extends="c:superBody" in its <aura:component> tag.
<!--c:subBody-->
<aura:component extends="c:superBody">
Child body: {!v.body}
</aura:component>
c:subBody outputs:
Parent body: Child body:
In other words, c:subBody sets the value for {!v.body} in its super component, c:superBody.
c:containerBody contains a reference to c:subBody.
<!--c:containerBody-->
<aura:component>
<c:subBody>
Body value
</c:subBody>
</aura:component>
In c:containerBody, we set the body attribute of c:subBody to Body value. c:containerBody outputs:
Parent body: Child body: Body value
'개발자정보' 카테고리의 다른 글
Lightning Datatable With Single Checkbox Selection (0) | 2022.04.16 |
---|---|
How To Convert Attachments To Files In Salesforce ? (0) | 2022.04.16 |
Age Of ‘Dock’ing (0) | 2022.04.16 |
Salesforce(세일즈포스) Quick Action Modal Popup Component 스타일 수정 방법 (0) | 2022.04.16 |
Salesforce의 하위 탭에서 상위 탭을 새로 고치는 방법 (0) | 2022.04.16 |