Se você já atuou em um grande projeto de Lightning, deve estar cansado de repetir o mesmo trecho de código toda vez que precisa interagir com uma Controller, não é mesmo? Então hoje quero te mostrar duas coisas legais, a primeira é o que o título do post diz, estender um componente do Lightning, e o que isso significa, isso significa que você pode aproveitar parte de um componente dentro de outro, mas fique tranquilo, isso fará sentido assim que começarmos a colocar a mão na massa, e segundo vamos fazer isso criando um componente que permitirá você fazer chamadas Apex com apenas 1 linha de código.
Entendendo o problema
Como eu disse antes, se você já trabalhou com grandes projetos em Lightning, muito provavelmente já precisou fazer uma chamada Apex para consumir dados do Salesforce, e se fez isso mais de uma vez, então você deve ter escrito o código abaixo algumas vezes, não é?
var action = component.get("c.getAccounts");
action.setParams(params);
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var result = response.getReturnValue();
//do something with the result
} else if (state === "INCOMPLETE") {
// wait, what?
} else if (state === "ERROR") {
var errors = response.getError();
//do something about the errors
}
});
$A.enqueueAction(action);
E sim, isso é chato e repetitivo, e tudo que é repetitivo pode ser de alguma forma, otimizado e essa é a ideia aqui hoje!
O resultado esperado
Bom, para facilitar a nossa vida, não seria mais fácil se pudéssemos simplesmente chamar uma classe do apex assim:
helper.apexMethod(component, "getAccount", { id : accountId})
.then(function (result) {
//Trate o result aqui!
})
Ou ainda, imagine escrever a sua query SOQL diretamente no componente do Lightning e ter o resultado de uma forma mais simples impossível:
helper.SOQL(component, "SELECT Id, Name, AnnualRevenue, Industry FROM Account WHERE Name Id = '" + accountID + "'")
.then(function (account) {
//Trate a account aqui!
})
Parece mágico, não? pois é exatamente isso que iremos fazer hoje, então chega de enrolação e vamos colocar a mão na massa.
Criando nossa Controller do Apex
A primeira coisa que vamos precisar, é uma Controller do Apex, capaz de falar com nosso componente do Lightning, e fazemos isso utilizando o annotation @AuraEnabled, o objetivo dessa nossa classe é ser um Helper para a execução de nossas futuras SOQLs diretamente de um componente Lightning, então nossa classe ficará assim:
public with sharing class ApexExtensionController {
@AuraEnabled
public static List<sObject> executeSOQL(String query) {
return Database.query(query);
}
}
Como você pode ver, nossa classe é bem simples, o nosso método executeSOQL receberá a query, executar e devolver os dados para o Lightning, mas como toda classe precisa de uma cobertura de teste, eu não ia te deixar na mão né, mas isso você pode pegar direto no meu Github.
Criando o Lightning Component
Chegou a hora de criamos o nosso Lightning Component que será estendido futuramente, ele será o responsável por fazer o meio do caminho entre os seus componentes e o Apex, bom se você chegou até aqui, acredito que já deve ter criado o seu primeiro componente em Lightning, então vou ser mais direto ao assunto e pular direto para a parte prática, sem ficar demostrando passo a passo de itens de menu, mas se tiver dúvidas, fala ai nos comentários que eu te ajudo sem problemas, ok?
Então vamos lá, vou chamar o nosso componente de ApexExtension, nome bem criativo, eu sei, nosso .CMP ficará assim:
<aura:component extensible="true" abstract="true" controller="ApexExtensionController">
{!v.body}
</aura:component>
Note um ponto interessante nesse componente, que é o extensible=”true”, isso indica que um componente do Lightning pode ser estendido por outros componentes, um outro atributo interessante aqui é o abstract=”true” isso garante a segurança do nosso componente, evitando que ele seja instanciado diretamente, até porque ele sozinho não servirá para nada não é mesmo?
O Helper do nosso componente ficará assim:
({
apexMethod: function (component, method, params) {
return new Promise(function (resolve, reject) {
var action = component.get("c." + method)
action.setParams(params)
action.setCallback(this, function (response) {
var state = response.getState()
if (state === "SUCCESS") {
resolve(response.getReturnValue())
} else if (state === "INCOMPLETE") {
// Really? Why??
} else if (state === "ERROR") {
var errors = response.getError()
if (errors && errors[0] && errors[0].message) {
console.log("Error message: " + errors[0].message)
reject(errors[0].message)
} else {
console.log("Unknown error")
reject("Unknown error")
}
}
})
$A.enqueueAction(action)
})
},
SOQL: function (component, query) {
return this.apexMethod(component, 'executeSOQL', {query: query})
}
})
Com isso, temos tudo pronto por aqui, agora é hora de consumir o que criamos, vamos lá?
Estendendo componente do Lightning
Agora é a hora em que a mágica acontece, vamos criar um componente que irá listar todos os contados de uma conta usando o novo método SOQL e também chamar o método de uma controller para obter o total de contatos associados a uma conta, e para isso vamos estender o componente que criamos antes, e utilizar os métodos novos que ganhamos \o/. Vale ressalvar que existem maneiras mais fáceis de fazer isso, mas o objetivo aqui é demostrar o uso do nosso Extender.
Abaixo como ficará nosso novo componente ContactList:
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" extends="c:ApexExtension" controller="ContactController">
<aura:attribute name="recordId" type="String" />
<aura:attribute name="records" type="List" />
<aura:attribute name="totalRecords" type="Integer" />
<aura:handler name="init" value="{!this}" action="{!c.initHandler}" />
<div>
<aura:iteration items="{!v.records}" var="contact">
<lightning:card title="{!contact.Name}"/>
</aura:iteration>
<div>Total Contacts: {!v.totalRecords}</div>
</div>
</aura:component>
Note o atributo extends=”c:ApexExtension” ele é responsável por estender o componente com base no nosso componente criado anteriormente.
E nossa controller do Lightning ficará assim:
({
initHandler : function(component, event, helper) {
const recordId = component.get('v.recordId')
const query = "SELECT Id, Name FROM Contact WHERE AccountId = '" + recordId + "'"
//Executa uma consulta SOQL
helper.SOQL(component, query).then(function(result){
component.set('v.records', result)
}).catch(function (error) {
console.error(error)
})
const params = {'accountId': recordId}
//Realiza uma chamada a um método do Apex
helper.apexMethod(component, 'totalContacts', params).then(function(result) {
component.set('v.totalRecords', result)
}).catch(function (error) {
console.error(error)
})
}
})
O nosso componente consome uma nova Apex Controller, quer será responsável por retornar o número total de contatos de uma conta, a nossa controller ficará assim:
public with sharing class ContactController {
@AuraEnabled
public static Integer totalContacts(Id accountId) {
return [SELECT COUNT() FROM Contact WHERE AccountId =: accountId];
}
}
Todos os códigos utilizados para esse exemplo estão disponíveis nesse Github.
Espero que isso os ajude a escrever componentes do Lightning com menos linhas e mais organizado.
Um forte abraço Trailblazers, e até o próximo post :)

Fernando Sousa
Senior Salesforce Developer
Bacharel em Sistemas da Informação pela Universidade de Taubaté (UNITAU) e MBA em Projeto de Aplicações para Dispositivos Móveis pelo IGTI – Instituto de Gestão em Tecnologia da Informação.
Comecei a programar bem cedo, por volta de 10 anos de idade, de maneira auto-didata passei por várias linguagens.
Em 2015 me conectei a plataforma Salesforce pela primeira vez, para fazer una integração entre um Aplicativos Mobile em android e o Salesforce Platform.
Atualmente com as certificações Salesforce Certified Platform Developer I, Salesforce Certified Platform App Builder, Salesforce Certified Platform Developer II, Salesforce Administrator e Sharing and Visibility.
Acompanhe meu Trailhead aqui.




