Sample Student App with multiple components and events and a lightning spinner – Part 1

by | Aug 28, 2018 | Lightning | 2 comments

So finally after a lot of gibberish texts I am able to present to you guys a working sample with a demo video. The video only contains the lightning app in action but don’t worry the code snippets will be made available shortly.

Sample Student App:

So here I am gonna show how to build a simple (not really a simple Hello World app because that’s not what we are here for) lightning app involving multiple components (with a hierarchy) and events and how they can save data and display the same in a list (Please don’t mind the poor UI for the list, I am gonna fix it the first chance I get).

I am also gonna show how to use a simple spinner to show progress of an action in lightning. In this case the saving of a student record.

You might have a few questions about events. Don’t worry about them for now, because I am gonna discuss everything at length and if you have any queries don’t hesitate to ask in the comments. For now, think of them as DOM events because they are quite similar.

Before I go any further,  I would like to share a pretty handy list of the various base components available as of Summer 18. Base components are nothing but some handy, ready made components provided to us by salesforce in order to enable us to build our components rapidly e.g. lightning:button, lightning:spinner (Yes, it is a base component). Here you go, Base Components in Lightning

I am gonna assume here that you do understand that Student (Student__c) is a custom object we have created here for the sake of storing data. If you don’t know what a custom object is, think of it as just a database table or a model in an ORM like Entity Framework or Hibernate. For detailed study refer to Custom Objects in Salesforce

In this example, we basically have two parts, one involving data insertion and the other being data retrieval. Both these operations require Aura methods meticulously placed inside an Apex Controller. Now, the data insertion form and the data display list are both individual components and they are communicating with each other using a simple event. So lets see what the Apex Controller looks like.

public with sharing class  StudentController {

    public static Student__c save(Student__c student){
       if(student == null)
           throw new AuraHandledException('student is null');
        insert student;
        return student;
    public static List getAllStudents(){
        return [select Id, Name, Age__c, Department__c from Student__c order by Id desc limit 10];


I would like to thank Chris Coyier for helping me figure out how to write code blocks in wordpress posts. Been searching since last night but couldn’t find something that works  until now. So thanks Chris!

Dissecting the Apex controller

with sharing

This essentially runs the Apex controller in the context of the logged in user and applies all the security settings for him/her when executing the code. This implies that a user who doesn’t have permission to do something won’t be able to do it even if the code has been written to do so. Like fetching a record the user doesn’t have access to or modifying a record he/she doesn’t have access to.


This exposes the method over the web so that a client side script can access it. The client side here is the Lightning component. This annotation can be also used with properties in a class to make it behave like a DTO in order to pass it as JSON to the client side.


This is a type of exception that is understood by the lightning component. If you wanna send a custom error message to the lighting component and expect it to understand and display an error message accordingly then you have to use this exception type. I will show you later how to handle an AuraHandledException.


The lightning component 


The markup (.cmp) file.

Remember how I told you this file is like the HTML page or the .aspx page or the cshtml page in .Net? This is what it looks like. This file is responsible for generating the html for the browser.

 <aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" 
                access="global" >
    <aura:attribute name="student" type="Student__c" 
                             'sobjectType' : 'Student__c',
                             'Name' : '',
                             'Age__c' : '',
                             'Department__c' : ''
                             }" />
    <aura:registerEvent name="updStudEvent" type="c:updateStudents" />
    <aura:registerEvent name="compEvent" type="c:CompEvent" />
        <lightning:spinner aura:id="spinner" variant="brand" alternativeText="Loading..."
    <fieldset class="slds-box slds-theme--default slds-container--small">
        <legend id="student-registration-form" class="slds-text-heading--smallslds-p-vertical--medium">
            Student Registration
        <form class="slds-form--stacked">
            <div class="slds-form-element"> <ui:inputText aura:id="name" class="slds-input" label="Name" value="{!v.student.Name}" required="true" placeholder="Enter name" /></div>
            <div class="slds-form-element"> <ui:inputNumber aura:id="age" class="slds-input" label="Age" value="{!v.student.Age__c}" required="true" placeholder="Enter age"/></div>
            <div class="slds-form-element"> <ui:inputText aura:id="dept" class="slds-input" label="Department" value="{!v.student.Department__c}" required="true" placeholder="Enter department" /></div>
            <div class="slds-form-element"> <lightning:button aura:id="btnSubmit" variant="brand" label="Submit" onclick="{!c.saveStudent}"/></div>

Overwhelmed? Relax. It is not as intimidating as it might appear to be. If you are really coming from a programming background then I expect you to understand at least this much. I won’t be explaining the HTML tags though.

First line, <aura:component> with attributes like implements, controller and access. What do they mean? implements implies that the component implements certain interfaces from the force/flexipage namespace. Implementing these interfaces gives some special abilities to the otherwise normal component.

force:appHostable- This implies the component can be included in a lightning tab.

flexipage:availableForAllPageTypes – This implies the component can be included in lightning pages.

flexipage:availableForRecordHome – This implies the component can be included in a lightning home page.

force:hasRecordId- This implies the component will have access to the record Id of the record page from which this component was invoked or where it is present. Works only if the component is present in a record detail page. Doesn’t work in lighting out.

There are other interfaces but lets stick to these for now. Also, you don’t need to implement all of these at once. Implement the ones that you think are necessary.

Controller attribute implies this is the server side Apex controller that the lightning component will depend on for data.

access=global This implies the component is globally accessible. Meaning it is accessible out of its namespace. Usually the namespace is c: for any org unless you change it to something else. Let’s you installed a managed/unmanaged package where the component’s access level is global. It indicates it can be used in your org even though the component has a different namespace.

There is a beautiful explanation here.

<aura:attribute> This defines a component variable on the markup. The student (of type Student__c) variable is used to capture the user input and flowing it back to the server. This variable can be bound to various markup elements using v. (dot). the attribute/variable name as you can see inside the form. Like {!v.student.Name}. The exclamation mark stands for two-way binding. # is used for one-way binding i.e, the value is only displayed but is not reflected back to the variable. Those who have used knockoutjs or angularjs would understand the concept of observable. This is something similar.

The two lines below it are event registration. Ignore them for now. We will get back to it later when we discuss events. Events are very useful and very important concept in lightning. They need to be discussed in detail and needs to be saved for later.


StudentFormController.js This is a javascript (.js) file. This is accessible from the markup. These 3 arguments are pretty straight forward. You can access the methods here from markup using c. (dot). Here c stands for the javascript controller file.

	saveStudent : function(component, event, helper) {
		console.log("Inside controller method");

StudentFormHelper.js – This is the helper file, also a javascript file. Think of it as a utility file. Contains most of the logic. The methods here are called from the controller.js file so as to keep the controller.js cleaner and uncluttered. Any reference to c.(dot) in this file doesn’t refer to the controller.js file. Don’t get confused. This c stands for the server side Apex controller.

    isValid : function(component) {
        console.log("Validating component");
        var student = component.get("v.student");
        return !($A.util.isEmpty(student.Name) || student.Age__c === 0 
                 || $A.util.isEmpty(student.Department__c));
    save : function(component){
        console.log("Saving component");
        var action = component.get("");
        //  console.log(JSON.stringify(component.get("v.student")));
            student: component.get("v.student")
        action.setCallback(this, function(response){
            //  console.log(response.getState());
            if(component.isValid() && response.getState()==="SUCCESS"){
                var blankStudent = {sobjectType:'Student__c',
                component.set("v.student", blankStudent);
                console.log("Firing appplication event");
                var updateStudentEvent = $A.get("e.c:updateStudents");
                        student : response.getReturnValue()
                console.log("Firing component event");
                var compEvent = component.getEvent("compEvent");
                console.log("StudentID:" + response.getReturnValue().Id);
                    studentID : response.getReturnValue().Id
            else if(response.getState()==="ERROR"){
                var errors = response.getError();
                    if(errors[0] && errors[0].message)
                    console.log("Unknown error!")

To be continued……..

Bishwambhar Sen
Bishwambhar Sen is an IT professional with over 10 years of industry experience. He is a Salesforce certified developer and admin. When he is not configuring and customising, he loves photography, traveling and blogging.
Subscribe To Our Newsletter

Subscribe To Our Newsletter

Join our mailing list to receive the latest news and updates from our team.

You have Successfully Subscribed!

Share This