Collections In Salesforce || List || Set || Map



Collections In Salesforce


Collections is a type variable which can store more number of records.

If you are new to salesforce you might be confusing more with Map in salesforce. Let's get clear on all types of collections in salesforce.

Variable : 

Variable is a container which holds the single value when the code is executed.

Eg1 : String str
We can store single value (Of string Type) in the Str.

Eg2 :Account Acc;
Acc can hold one account record at a time.

But As Salesforce Developer it is best practice to follow bulkification instead of using single variables .

List collection Type : 


List is collection of similar datatypes stored in the single variable .

We can assign the values to the list dynamically. List allows duplicate values to stored.

Example :
List<account> accList=new List<account>();

AccList can hold any number of accounts .

/*Go to Developer Console>>Debug>>Open Execute Anonymous Window and execute the following code*/

List<account> accList=new List<account>();

for(Integer i=0;i<5;i++) {

    Account a = new Account(Name='TestAccount' + i);

    accList.add(a);

}

System.debug('Accounts stored in the AccList is  :'+accList);

Once it is executed click on Debug check box for the records stored in accList.

AccList contains five account records in its five indexes .

Index 0 --contains account1
Index 1 --contains account2
Index 2 --contains account3
Index 3 --contains account4
Index 5 --contains account5

List Methods :


List Methods used to perform different actions on the data stored in the List .

For example List.add() method adds the elements to the existing List .

We also have many other methods in the list class as mentioned below .
  • 1.AccList.size()--Returns Size of the List.
  • 2.AccList.clear()--Delete all the records stored in the list .
  • 3.AccList.clone()--Create duplicate copy of existing list .
  • 4.List.contains('test')--Search for the element mentioned between brackets and                                                        returns trueif it matches with the existing list .
There are many other methods present in the List Class apart from above mentioned .Please refer below link for further details .

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_methods_system_list

Set collection Type : 


Set is similar to List collection type ,The only difference is Set does not allow duplicate values .

Example :
Set<String> strList=new Set<String>();

strList.add('Maisel');
strList.add('Tom');
strList.add('Reade');
strList.add('Reade');// Trying to add duplicate variable .But Set does not store it for second time.

System.debug('Accounts stored in the strList is  :'+strList);

Once it is executed click on Debug check box for the records stored in accList.

You can see strList contains only three values(Maisel,Tom and Reade).

Map collection Type : 


Map is key value pair which contains unique key for each value .

Funny and Easy Example :Assume all the rooms in an apartment is values in the map and each key to unlock the room is Key in the map .  Each room has unique Key to unlock the room and no two keys will be same in an entire apartment . Believe us this examples make the map simpler to understand .

Don't get angry if your apartment have same keys to open two rooms ☺☺☺(Ignore My Strange Jokes).

Example 1 :
Map<Integer,String>  myMap= new Map<Integer,String>();

//Inserting the values into the map
myMap.put(1,'FirstElement');
myMap.put(2,'SecondElement');
myMap.put(3,'ThirdElement');
myMap.put(4,'FourthElement');
myMap.put(5,'FifthElement');

//Now myMap contains five values associated with the five keys(Unique)

Example 2 :
/*Go to Developer Console>>Debug>>Open Execute Anonymous Window and execute the following code*/

List<account> accList=new List<account>();

accList=[select id,Name from account Limit 20];//Querying the existing records into the list
Map<Id,Account>  accMap= new Map<Id,Account>();

for(Account acc:accList) {

 accMap.put(acc.id,acc); // Adding the accountID as key and Account record as value to the accMap

}

System.debug('Accounts stored in the accMap as Key-value pair   :'+accMap);

Once it is executed click on Debug  . You can see Id of the record on left side(Key) and Account record on right side(Value) .

Map Methods : 


Map methods used to perform actions on the Map like adding the values to map and getting the value of the map by passing the key .

Example1 :
Map.put(Key,Value)--Used to store the new values into the map dynamically as shown in                                                        above example.
Example2 :
Map.get(Key)--Map returns the value matching the key passed .

Again from our funny example ,Once you entered into the apartment you will be given with key to open the room

Likewise if you pass the id of the account ,Map will be returned with the account record .

accMap.get('0010I00002Juvstyu');//Returns the account record with id '0010I00002Juvstyu'

Usage Of Salesforce Collections in Apex Trigger :

//The below Trigger helps to ignore duplicate emails in the Author object .

trigger DemoTrigger2 on Author__c (before insert,before update) {
    List<Author__c> accList=new List<Author__c>([select Author_Email__c from Author__c]);
    map<String,Author__c> accmap=new map<String,Author__c>();
    for(Author__c acc:accList){
        accmap.put(acc.Author_Email__c,acc);
    }
    
    if(Trigger.isinsert&&Trigger.isbefore){
        for(Author__c acc:Trigger.new){
            if(accmap.get(acc.Author_Email__c)!=null){
                acc.adderror('Email already exists');
            }
        }
    }   
}

Sales Force Basic Apex Class examples

Apex Class Examples for Salesforce Developer Beginners


1. Insert the account record by receiving the input parameters .

Create new apex class from the Developer Console and enter 'Demo1' for the class name .

Public Class Demo1
{
    Public void CreateAccount(String Name, String Phone){
        account acc=new account();
       
        acc.Name=Name;
       
        acc.phone=Phone;
       
        insert acc;
       
        System.debug('Account Inserted :'+acc.name);
    }
   
}

Demo1 class receives two input parameters (Name&&Phone) ,By using the input parameters CreateAccount method insert the new account record into the sales force database .

Out Put :

/*Go to Developer Console>>Debug>>Open Execute Anonymous Window and execute the following code*/

Demo1 ac= new Demo1();

ac.CreateAccount('testAccount','123456789');

Once the above code executed successfully check the newly created account record from the Accounts Tab .

Note :For test purpose we have used Open Execute Anonymous Window to execute the written codes. Please note that we can also invoke the apex class by using below methods :

  • Apex Trigger .
  • Visualforce Page Controller.
  • Process Buider .
  • Apex methods(Other methods)
  • From External source(eg. By using Rest/Soap integrations)



2.Static Vs Non Static Methods


Public Class Demo2{
    Public static void Method1(){
       
        System.debug('This is static method');
       
    }
   
    Public void method2(){
       
        System.debug('This is Non static method');
       
    }
   
}

Most of the beginners conflict between usage of Static/Non-Static invocation .Demo2 class will explains difference in invoking the Static and non static methods

Out Put :

For static methods we invoke by using class name dot method name directly like below

/*Go to Developer Console>>Debug>>Open Execute Anonymous Window and execute the following code*/

Demo2.Method1();  //Static Method

For Non static methods we invoke them by creating instance of the class like below

Demo2 dm= new Demo2();//Non-Static Method 
dm.Method2();

If you try vice-versa you will receive an error .



3.Retrieving object Records by passing Single field value to the method.

Public class Demo3
{
   
    Public static void FetchAccName(String p) { 
        Set<String> s1= new Set<String>();
       
        List<Account> acc=[Select id, Name From Account where phone=:p];
       
        for(Account a:acc)
           
        {
           
            String s =a.name;
           
            s1.add(s);
           
        }
       
        System.debug('The Account Record Matching the Phone' +s1);
    }
   
}

The FetchAccName method receives phone number as a parameter and search for an account with that number in the existing records.

Out Put :

/*Go to Developer Console>>Debug>>Open Execute Anonymous Window and execute the following code*/

Demo3.FetchAccName('74857937');//Provide phone number which exists in your database .

Once it is executed click on Debug check box for the records which matching the phone number



4. Creation of Account,associated contact and opportunity in single transaction .

Public class Demo5
{
   
   public static void Createrecords(String n)
       
    {
       
        Account a = new Account();
       
        a.Name=n;
       
        insert a;
       
        System.debug('Account :' +a.name);
       
        Contact c = new Contact();
       
        c.LastName='Dinesh';
       
        c.AccountId=a.id;//Id of the Account which we have created above
       
        insert c;
       
        System.debug('Contact :' +c.Lastname);
       
        Opportunity opp= new Opportunity();
       
        opp.Name='Test Opportunity';
       
        Date d= Date.newinstance(2012,2,17);
        opp.CloseDate=d;
        opp.StageName='Closed Lost';
        opp.Accountid=a.id;  //Id of the Account which we have created above
       
        insert opp;
       
        System.debug('Opportunity :' +opp.name);
       
    }
   
}

Createrecords method receives string parameter and creates account ,contact and Opportunity and also associates account with contact and opportunity by using the AccountID .

Out Put :

/*Go to Developer Console>>Debug>>Open Execute Anonymous Window and execute the following code*/

Demo5.Createrecords('Demo5account');   //Invoking the class by passing the parameters.


5. Allowing partial success of the records and storing the records which have failed with errors .


public class Demo5 {
    
    public static void createaccount(List<account> accts){
        List<account> failedList =new List<account>();
        Map<account, String> errorMap =new Map<account, String>();    
        Database.SaveResult[] srList = Database.insert(accts, false);
        
        for (Database.SaveResult sr : srList) {
            if (sr.isSuccess()) {
                System.debug('Successfully inserted account. Account ID: ' + sr.getId());
            }
        }
        //Collecting failed List
        for (Integer i = 0; i < accts.size(); i++) {
            Database.SaveResult s = srList[i];
            account origRecord = accts[i];
            if (!s.isSuccess()) {
                List<Database.Error> e= s.getErrors();  
                errorMap.put(origRecord,e[0].getMessage());
                failedList.add(origRecord);     
            } 
            
        }
        
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {'youremail@email.com'};
            mail.setToAddresses(toAddresses);
            mail.setSubject('Below insertion of the accounts have been failed ');
            mail.setPlainTextBody('Failed Account List'+errorMap);
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });   
    }    
}

Demo5 class receives the list of accounts and try to insert them into the database. If the input records are failed to insert then user will get email notification with the failed records list along with the error message.

Out Put :

/*Go to Developer Console>>Debug>>Open Execute Anonymous Window and execute the following code*/

List<account> accts=new List<account>();
for(Integer i=0;i<10;i++) {
    Account a = new Account(Name='TestAccount' + i);
    accts.add(a);
}//Above records will get inserted if your account object does not have any other validations

account acc=new account();
accts.add(acc);//Adding the account without providing the mandatory field(Account Name) .This //record will not be inserted since this does not have mandatory field AccountName .
demo6.createaccount(accts);//Passing the accts list to creteaccount method

If you have mentioned your email in the code ,You would have been received email containing the failed record and error message .

7. Usage of DescribeSObjectResult Class methods .

DescribeSObjectResult Class contains methods for retrieving the sales force object metadata details .

VisualForce Page :


<apex:page controller="Demo8">
  <apex:form >
   <apex:selectlist size="1">
     <apex:selectoptions value="{!options}"></apex:selectoptions>
   </apex:selectlist>
  </apex:form>
</apex:page>

Apex Controller :
    
    public Demo8(){
        
        options = new List<SelectOption>();
        Schema.DescribeSobjectResult r = Account.SobjectType.getDescribe();
        List<Schema.childRelationship> c = r.getChildRelationShips();
        
        for(schema.childRelationship x:c){
            String name = ' '+x.getChildSObject();
            SelectOption op = new SelectOption(name,name);
            options.add(op);
        }    
    }
}

If you run the page it will show you all the child objects of account .You can also use the same logic for custom objects .

*********************************************************************
We hope you are clear with the process now .

If you still require further clarifications,Please let us know in the comments .

Happy Learning☺☺☺


Apex Managed Sharing With Real Time Example In SaelsForce

Apex Managed Sharing In Salesforce :


Reason For Usage Of Apex Sharing :

The client might required to share the record access to different set of users based on COMPLEX CRITERIA/CONDITIONS  which cannot be done using sales force native features like Sharing Rules/OWD.

Apex Sharing :
Providing Sobject Access to targeted user by using Apex is called Apex Sharing.

By Default if OWD of the object is not set to most permissive access level(Public Read/Write) ,Then there will be automatically share object created for the existing object .
For Example if OWD for 'Account' is not set to Public Read/Write then 'AccountShare' object will be existing in the back-ground .
ScreenShot 1:


Share Object Technical Details :

Like Account object have different fields existed ,In the Same way Share object also contains the set of fields .Please find the below table.


Field Name
Field Description
ParentId
Salesforce ID of the record  for which you wanted to share the access to targeted users.
AccessLevel
Level of access to be shared with target user or Group
UserOrGroupId
The ID of the User whom you wanted to share the access. The ID can also be Public Group ID or Role ID
RowCause(Apex Sharing Reason)
Reason for providing the access .This will differentiate weather access provided by OWD or Sharing Rules or Apex Sharing.

Scenario Based Example:

Prerequisite:

Objects Used in the discussion:

1.Project--Object contains all the business task details which require to be completed .

2.Project Member--Are the members who work on the project which has assigned to them.
   Project Member is junction object which is master-Detail with Project and Contact


3.Contact--Sales force Contact Object
   Assume all the contacts Owner is assigned with their own User ID .
Eg .We have user Kris who is also Owner for associated contact named Kris .

Use Case :

1.Whenever status of the project changed from 'New' to 'Assigned' The respective project record access should be shared with all the Project Members .

2.Once the Project Members completed their assigned task and Status of the Project changes to 'Completed' then Access should be Revoked/Removed from the Project Team Members .

Solution: 

We require to create Apex Trigger on Project object and create the share object records and delete the access after Project completed

The below Trigger collects all the project records for which status changed to 'Assigned' Or changed to 'Completed' and send them to Apex class to create and Revoke the access respectively  by using apex sharing .

Apex Trigger :

trigger ProjectShare on Project__c (before insert,after update) {
 
    List<Project__c > projectShareList=new List<Project__c >();
 
    List<Project__c > revokeShareList=new List<Project__c >();
 
    //Share the access 
 
    if(Trigger.isafter&&Trigger.isUpdate){
     
        for(Project__c Pro:Trigger.new){
         
            if(Pro.Status__c=='Assigned'&&trigger.oldmap.get(Pro.id).Status__c!='Assigned'){
             
                projectShareList.add(Pro);
             
                system.debug('Share the access'+Pro.id);
             
            }
         
        }
       
        if(projectShareList!=null){
           
            ProjectShareclass.provideAccess(studyshareList);
             
        }
     


        //Revoke the access
     
        for(Project__c Pro:Trigger.new){
         
            if(Pro.Status__c!='Assigned'&&trigger.oldmap.get(Pro.id).Status__c=='Assigned'){
             
                system.debug('Revoke the access'+Pro.id);
             
                revokeShareList.add(std);
             
            }
         
        }
        if(revokeShareList!=null){
         
            ProjectShareclass.revokeAccess(revokeshareList);
         
        }
    }
}

Apex Class :

    public static void  provideAccess(List<Project__c > pros){
     
        List<Project_member__c> tmList=new List<Project_member__c>();
     
        map<id,Project_member__c> tmmap=new map<id,Project_member__c>();
     
        List<Project__Share> shareList=new List<Project__Share>();
     
       tmList=[select id,project__c,MasterDetailWithcontact__r.owner.id from 
Project_member__c where project__c IN:pros];
     
        userList=[select id from user];
     
        for(Project_member__c s:tmList){
         
            tmmap.put(s.Project__c,s);
         
        }
     
        for(project_c rec:Pros){
         
            Project__Share share=new Project__Share();
         
            share.ParentId = rec.id; 
         
            share.AccessLevel = 'Edit';
         
            share.RowCause = Schema.Project__Share.RowCause.Manual;
         
            share.UserOrGroupId = tmmap.get(rec.id).MasterDetailWithcontact__r.owner.id;
         
            shareList.add(share);
         
        }
     
        insert shareList;
     
    }
 
    public static void  revokeAccess(List<Project__c> pros){
     
        List<Project__Share> shareList=new List<Project__Share>();
     
        shareList=[select id from Project__Share where parentId IN:pros AND RowCause = 'Manual'];
     
        delete shareList;
    }
}

Result :

Once the project record is created into the database ,By default only owner of the record will have access to record as shown in Screenshot 2 :

Screenshot 2:



Once the above project record updated to the 'Assigned' status  ,Access of the project record will be shared to project team member . Please find the ScreenShot 3.

First Share record with all access Level belongs to the default record owner access . And Second Share record with Edit access and RowCause 'Manual' belongs to Share record created by above Apex trigger and Apex class.

ScreenShot 3 :





If you update the Status to 'Completed' again the 'Edit' access would be revoked/Deleted to all the Project Members associated to Project object.
*********************************************************************
We hope you are clear with the process now .

If you still require further clarifications,Please let us know in the comments .

Happy Learning☺☺☺

Object Level Access Vs Record Level Access in Salesforce

Object Level Access Vs Record Level Access  :

If you are new to Salesforce you might have conflicted between Object Level Access and Record Level Access .  Don't worry at the end of the article you will be clear with both of them .

In salesforce you can allow specific users to access specific fields in a specific object and then restrict the each user to which records they are allowed to see . 

To control data access promptly, you can allow particular users to view specific fields in a specific object, but restrict the individual records they're allowed to see.

Object Level Access : 

First Decide which objects a specific user should have access to .
Let us take an example :We have object Called Student and we have also have users                           userA,userB with ProfileX and UserC,UserD with ProfileY. 

Step 1 : Here let us take an object 'Student' to understand the process easily ,First Decide who are all should have access to Student Object. 
 Ans :All the users present in ProfileX should have access to Student object .

Step 2:Since only ProfileX users should have access to Student object ,we will give read/edit/create access to ProfileX .

Till now you have only provided Object Level Access. From the above access user A can read/edit/create ONLY his own records. He cannot access UserB owned records even though UserB is from same profile .

Record Level Access : 

This Will decide which user has access to what records individually. 
Open Setup>Sharing Setting 

Here you will have below option to provide for individual object :

1.Private (Only Record owner and System Administrator can have access to records)
2.Public Read Only(All users can view the records)
3.Public Read/write(All Users can view/Edit records)

Since you wanted to provide student object access to only set of users ,Provide OWD(Organization Defaults/Sharing Settings) to Private .

Now Access level for Student Object is Private and ProfileX has read/edit/create access,All the users under ProfileX can read Create/Read/Edit their Own records .

Example : 

UserA created Tony student Record .

UserB created Victor student Record .

Now UserA can have only access to Tony student Record .UserA cannot access UserB's Victor student Record record even though both are from same profiles, Since OWD is Private users cannot access each other's data .

If other users require access to all the Student records irrespective of  the Owner , Then we can extent access by using Sharing rules or Apex Sharing . 

We will discuss more about Apex Sharing in other Posts .

We hope you are clear with the process now .

If you still require further clarifications,Please let us know in the comments .

Happy Learning☺☺☺

Aura Components Basics Fully Explained with all the codes

Aura Components Basics : 

Aura Components Basics module is first step to learn Salesforce Lightning .If you wanted to start learning the Lightning , this module would the best option you have . Module covers from very basic understad to advanced understaing .Even though this module requires more time to be spent but it would be worth learning .Once you have started the module if you any errors in the codes you can refer in this blog .

High Level Explanation : 
step 1:The expenseApp starts the flow .
step 2:and invokes 'expenses' component.
step 3:expenses component calls 'expenseForm' component :
       <lightning:layoutItem padding="around-small" size="6">
            <c:expenseForm/>
        </lightning:layoutItem>

step 4:expenseForm cmp is responsible for form to create new expense record.
step 5:By using 'expensesItemUpdate' event ,expenseform sends newexpense record to be commited to data base
        to expense cmp .
step 6: expense componet handles the event fired from expense form in step5 with new expense record .
          <!--Event for creating the expense form-->
                <aura:handler name="createExpense" event="c:expensesItemUpdate"
                  action="{!c.handleCreateExpense}"/>

step 7: By using step 6 expense cmp commit the new expense form to database

step 8: From the UI if user checks/unchecks IsReimbursed? check box it will
        also commited to datebase using the event fired from expenseItem cmp
        <aura:registerEvent name="updateExpense" type="c:expensesItemUpdate"/>

 
*****************   Expense App  *************************

<aura:application extends="force:slds" >
    <c:expenses/>
</aura:application>

*****************  Expense App End  *************************



*****************   expenses.cmp  *************************

<!--expenses-->
<aura:component controller="ExpensesController">
    <aura:attribute name="expenses" type="Expense__c[]"/> 
 
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
    <!--Event for updateing isReimbursed? checkbox-->
    <aura:handler name="updateExpense" event="c:expensesItemUpdate"
                  action="{!c.handleUpdateExpense}"/>
    <!--Event for creating the expense form-->
    <aura:handler name="createExpense" event="c:expensesItemUpdate"
                  action="{!c.handleCreateExpense}"/>
    <!-- NEW EXPENSE FORM -->
    <lightning:layout >
        <lightning:layoutItem padding="around-small" size="6">
            <c:expenseForm/>
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / NEW EXPENSE FORM -->
    <lightning:layout>
        <lightning:layoutItem padding="around-small" size="6">
            <c:expensesList expenses="{!v.expenses}"/>
        </lightning:layoutItem>
        <lightning:layoutItem padding="around-small" size="6">
            <!-- Put something cool here-->
        </lightning:layoutItem>
    </lightning:layout>
 
 
</aura:component>

*****************   expenses.cmp end  *************************



*****************   expenses.JS *************************

<!--expenses-->
<aura:component controller="ExpensesController">
    <aura:attribute name="expenses" type="Expense__c[]"/> 
 
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
    <!--Event for updateing isReimbursed? checkbox-->
    <aura:handler name="updateExpense" event="c:expensesItemUpdate"
                  action="{!c.handleUpdateExpense}"/>
    <!--Event for creating the expense form-->
    <aura:handler name="createExpense" event="c:expensesItemUpdate"
                  action="{!c.handleCreateExpense}"/>
    <!-- NEW EXPENSE FORM -->
    <lightning:layout >
        <lightning:layoutItem padding="around-small" size="6">
            <c:expenseForm/>
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / NEW EXPENSE FORM -->
    <lightning:layout>
        <lightning:layoutItem padding="around-small" size="6">
            <c:expensesList expenses="{!v.expenses}"/>
        </lightning:layoutItem>
        <lightning:layoutItem padding="around-small" size="6">
            <!-- Put something cool here-->
        </lightning:layoutItem>
    </lightning:layout>
 
 
</aura:component>

*****************   expenses.JS  end*************************



*****************   expenses.Helper  *************************

({
    createExpense: function(component, expense) {
        var action = component.get("c.saveExpense");
        action.setParams({
            "expense": expense
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                var expenses = component.get("v.expenses");
                expenses.push(response.getReturnValue());
                component.set("v.expenses", expenses);
            }
        });
        $A.enqueueAction(action);
    },
        updateExpense: function(component, expense) {
        var action = component.get("c.saveExpense");
        action.setParams({
            "expense": expense
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                // do nothing!
            }
        });
        $A.enqueueAction(action);
    },

})

*****************   expenses.Helper end *************************


*****************   expenseForm.cmp  *************************

<aura:component >
    <aura:attribute name="newExpense" type="Expense__c"
                    default="{ 'sobjectType': 'Expense__c',
                             'Name': '',
                             'Amount__c': 0,
                             'Client__c': '',
                             'Date__c': '',
                             'Reimbursed__c': false }"/>
 
    <aura:registerEvent name="createExpense" type="c:expensesItemUpdate"/>
    <!-- PAGE HEADER -->
    <lightning:layout class="slds-page-header slds-page-header--object-home">
        <lightning:layoutItem>
            <lightning:icon iconName="standard:scan_card" alternativeText="My Expenses"/>
        </lightning:layoutItem>
        <lightning:layoutItem padding="horizontal-small">
            <div class="page-section page-header">
                <h1 class="slds-text-heading--label">Expenses</h1>
                <h2 class="slds-text-heading--medium">My Expenses</h2>
            </div>
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / PAGE HEADER -->
    <lightning:layout>
        <lightning:layoutItem padding="around-small" size="6">
            <!-- CREATE NEW EXPENSE -->
            <div aria-labelledby="newexpenseform">
                <!-- BOXED AREA -->
                <fieldset class="slds-box slds-theme--default slds-container--small">
                    <legend id="newexpenseform" class="slds-text-heading--small
                                                       slds-p-vertical--medium">
                        Add Expense
                    </legend>
                 
                    <!-- CREATE NEW EXPENSE FORM -->
                    <form class="slds-form--stacked">       
                        <lightning:input aura:id="expenseform" label="Expense Name"
                                         name="expensename"
                                         value="{!v.newExpense.Name}"
                                         required="true"/>
                        <lightning:input type="number" aura:id="expenseform" label="Amount"
                                         name="expenseamount"
                                         min="0.1"
                                         formatter="currency"
                                         step="0.01"
                                         value="{!v.newExpense.Amount__c}"
                                         messageWhenRangeUnderflow="Enter an amount that's at least $0.10."/>
                        <lightning:input aura:id="expenseform" label="Client"
                                         name="expenseclient"
                                         value="{!v.newExpense.Client__c}"
                                         placeholder="ABC Co."/>
                        <lightning:input type="date" aura:id="expenseform" label="Expense Date"
                                         name="expensedate"
                                         value="{!v.newExpense.Date__c}"/>
                        <lightning:input type="checkbox" aura:id="expenseform" label="Reimbursed?"
                                         name="expreimbursed"
                                         checked="{!v.newExpense.Reimbursed__c}"/>
                        <lightning:button label="Create Expense"
                                          class="slds-m-top--medium"
                                          variant="brand"
                                          onclick="{!c.clickCreate}"/>
                    </form>
                    <!-- / CREATE NEW EXPENSE FORM -->
                 
                </fieldset>
                <!-- / BOXED AREA -->
            </div>
            <!-- / CREATE NEW EXPENSE -->
        </lightning:layoutItem>
    </lightning:layout>
</aura:component>

*****************   expenseForm.cmp end  *************************


*****************   expenseForm.JS   *************************

({
clickCreate: function(component, event, helper) {
        var validExpense = component.find('expenseform').reduce(function (validSoFar, inputCmp) {
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // If we pass error checking, do some real work
        if(validExpense){
            // Create the new expense
            var newExpense = component.get("v.newExpense");
            console.log("Create expense: " + JSON.stringify(newExpense));
            helper.createExpense(component, newExpense);
        }
    },
})

*****************   expenseForm.JS end  *************************


*****************   expenseForm.Helper *************************

({
    createExpense: function(component, newExpense) {
        var createEvent = component.getEvent("createExpense");
        createEvent.setParams({ "expense": newExpense });
        createEvent.fire();
    },

})

*****************   expenseForm.Helper end    *************************



*****************  expensesItemUpdate.event  *************************

<!--expensesItemUpdate-->
<aura:event type="COMPONENT">
    <aura:attribute name="expense" type="Expense__c"/>
</aura:event>
*****************   expensesItemUpdate.event  End *************************


*****************   expensesList.cmp  *************************

<!--expensesList-->
<aura:component>
    <aura:attribute name="expenses" type="Expense__c[]"/>
    <lightning:card title="Expenses">
        <p class="slds-p-horizontal--small">
            <aura:iteration items="{!v.expenses}" var="expense">
                <c:expenseItem expense="{!expense}"/>
            </aura:iteration>
        </p>
    </lightning:card>
</aura:component>

*****************   expensesList.cmp End *************************


*****************  expenseItem.cmp  *************************

<!--expenseItem-->
<aura:component>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <aura:attribute name="formatdate" type="Date"/>
    <aura:attribute name="expense" type="Expense__c"/>
    <aura:registerEvent name="updateExpense" type="c:expensesItemUpdate"/>

    <lightning:card title="{!v.expense.Name}" iconName="standard:scan_card"
                    class="{!v.expense.Reimbursed__c ?
                           'slds-theme--success' : ''}">
        <aura:set attribute="footer">
            <p>Date: <lightning:formattedDateTime value="{!v.formatdate}"/></p>
            <p class="slds-text-title"><lightning:relativeDateTime value="{!v.formatdate}"/></p>
        </aura:set>
        <p class="slds-text-heading--medium slds-p-horizontal--small">
           Amount: <lightning:formattedNumber value="{!v.expense.Amount__c}" style="currency"/>
        </p>
        <p class="slds-p-horizontal--small">
            Client: {!v.expense.Client__c}
        </p>
        <p>
            <lightning:input type="toggle"
                             label="Reimbursed?"
                             name="reimbursed"
                             class="slds-p-around--small"
                             checked="{!v.expense.Reimbursed__c}"
                             messageToggleActive="Yes"
                             messageToggleInactive="No"
                             onchange="{!c.clickReimbursed}"/>
        </p>
    </lightning:card>
</aura:component>

*****************   expenseItem.cmp End  *************************


*****************   expenseItem.JS  *************************

({
    doInit : function(component, event, helper) {
        var mydate = component.get("v.expense.Date__c");
        if(mydate){
            component.set("v.formatdate", new Date(mydate));
        }
    },
 

    clickReimbursed: function(component, event, helper) {
        var expense = component.get("v.expense");
        var updateEvent = component.getEvent("updateExpense");
        updateEvent.setParams({ "expense": expense });
        updateEvent.fire();
    },
})

*****************   expenseItem.JS End  *************************

*****************   expenseItem.style  *************************

.THIS.slds-card.slds-theme--success {
    background-color: rgb(75, 202, 129);
}

*****************   expenseItem.style End  *************************

*****************   ExpensesController.apex  ServerSideController  *************************

public with sharing class ExpensesController {
    // STERN LECTURE ABOUT WHAT'S MISSING HERE COMING SOON
    @AuraEnabled
    public static List<Expense__c> getExpenses() {
        return [SELECT Id, Name, Amount__c, Client__c, Date__c,
                       Reimbursed__c, CreatedDate
                FROM Expense__c];
    }
 
     @AuraEnabled
    public static Expense__c saveExpense(Expense__c expense) {
        // Perform isUpdateable() checking first, then
        upsert expense;
        return expense;
    }
}
*****************   expenseItem.apex End  *************************



We hope your clear with the process now .

If you still require further clarifications,Please let us know in the comments .

Happy Learning☺☺☺