Skip to main content

Salesforce PD 1 Notes

Salesforce PD1 Notes and Guide


Hi everyone, Adding PD1 notes. It is very lengthy but will help you in getting the right guidance for your journey. I will keep making it learner friendly. Do mail at guide2salesforce@gmail.com for any suggestion/feedback. All the best.


What is Apex ? -

1. Apex is a programming language of salesforce . It is a strongly typed , object oriented programming language .

Stronly typed language:-  strongly typed language means it is mandatory to specify the data type of the variable to specify what type of value you want to store in the variable..
e.g. Java , Apex , C# etc are strongly typed language whereas if we will take javascript , Javascript is a loosely typed programming language. In javascript we will always be using the var keyword to declare the variable irrespective of what value has been stored in the variable.
var x=20;
var y='ABC';

Object Oriented Programming :- Object Oriented programming is a methodology of programming . There are many language which are on OOps concepts such as C# , C++ , Java etc..

2. The apex code is saved on the force.com platform provided by the salesforce . It is saved , compiled and executed on the Force.com server.

3. Apex is a case -insensitive programming language . Uppercase and lowercase will be treated as same in case of Apex . e.g. a is equivalent to A.

4. Apex runs on Multitenant architecture so we need to work under the different governor limits provided to us. for example there is a limit that in a single transaction I cant have more than 150 DML statements.

5. Apex is easy to test.

6. Apex is by default connected with the database , Apex provides direct access of the data and provide different DML statements to modify the data.

7. Apex code upgrades automatically whenever salesforce modifies the any of its functionality.

Writing First Program of Apex :-
--------------------------------
Go to the org - From the Set up icon - Developer console

Now lets create a class:- file - new - apex class- provide the name of your class.

public class Demo1 {
    
    //This is a static method of my class and you know that static methods can be called directly with the classname
    public static void sayHello(){
        System.debug('Hello Everyone.. How r u?? Ur developer module has not started . Please pay attention and complete all the modules of the trailhead');
    }

}

Now , lets call the method of the class :-

Debug - OPen execute anonymous window: and now write :-


Demo1.sayHello();

select Open Log and click on execute button

Apex Variables and data types :-
------------------------------
What is a variable ?- A variables is a container which is used to store some variable of specified data type..
Syntax :-
data-type variableName=value;

Primitive (basic) Data types of Apex :-

1. Integer :- (-2117483648 to +2117483647) 

Integer age=25;
System.debug('age - '+age);

2. Long :- If you want to store some value which is not in the integer data type then we can use Long as the data type..Long literal (value) should be used with l .

long creditCardNum=856532051313135462l;
System.debug('Credit Card Num '+creditCardNum);
3. double  :- If we want to store the decimal values then decimal or double can be used.. For double we need to use suffix as d

decimal salary=85000.85;
System.debug('Salary : '+salary);

4. decimal  :- Mainly used to store currency values. 

5. String :- here string will come in single quotes.

string name='ABC';
System.debug('Welcome '+name);

6. Date :-

Date d=Date.today();
System.debug('Today Date : '+d);

7. DateTime :-

DateTime dt=DateTime.now();
System.debug('Date Time : '+dt);

8. Time :- 

DateTime dt=DateTime.now();
System.debug('Date Time : '+dt);

Time t=dt.time();
System.debug(t.hour()+':'+t.minute()+
            ':'+t.second());
 
Note :- All the variables will be initialized null if we have not initialized them.

Implicit Type conversion and Explicit type conversion:-
-------------------------------------------------------

e.g. of Implicit type conversion

integer i=25;
long l=i;  //Here i will be implicitly converted to long 
System.debug('Long l = '+l);

e.g. of Explicit type conversion

/*Here writing l is not required with the value bcz the literal is in the range of integer so here implicitly integer is getting stored into long..*/
long l=259532;  //Implicit conversion 
integer i=(integer)l; // explicit conversion
System.debug('Integer i = '+i);

 

Links for the revision of the topics like Collection, Sobject and SOQL:
 
·     https://www.youtube.com/watch?v=C7K2b5g6tz4
 
·     https://www.youtube.com/watch?v=2YcX4Myr0bo
 
·     https://www.youtube.com/watch?v=otOvxx321AU
 
·     https://www.youtube.com/watch?v=1w_ErSBclR4


sObject :-


  1. sobject is one of the data type that salesforce supports.

  2. sObject is used to represent a record of an object in the apex . Whenever we are fetching a record of an object in apex , that record will be represented as Sobject and whenever we want to insert a record in salesforce org so first of all we have to create a sobject and then need to insert..


Any record of an salesforce object will be represented as sobject when working in apex.


e.g.  Want to fetch a record from the salesforce org and store it in a variable? That record will be store in sobject variable.. 


/*Account is not a class here , we know Account is a standard object in salesforce , 

here acc is a variable of sobject type which is my account in this case*/


Account acc=[select ID,Name,Industry,Rating from Account where Name='Genepoint'];

System.debug(acc.Id+' '+acc.Name+' '+acc.Industry+' '+acc.Rating);




e.g. 2:- 


//I want to insert a record in salesforce org , so first of all I need to create 

//a sobject variable representing that record..

Account acc=new Account();  //Here we have initialized an sobject of Account type..

acc.Name='Test Account from Apex';

acc.Industry='Banking';

insert acc; //This will insert a record in salesforce org through apex..


System.debug('Account Inserted Succesfully...');



Note 1:- sobject represents a record of a salesforce object. If we want to represent multiple records then that can be represented by List of SObject type.


Note 2:- If we are aware that the specific type of record then we can use the sobject

object specific type as we have above.. Otherwise we can also have the generic sObject type..


//specific sobject type

Contact c=[select Id,firstName,lastName from contact where firstName='Lakshay'];

System.debug(c.Id+' '+c.firstName+' '+c.lastName);


//generic sobject type

SObject obj=[select Id,firstName,lastName from contact where firstName='Lakshay'];

//Now from sObject type we cant access the specific fields of Contact object I 

//need to downcast it..

Contact cObj=(Contact)obj;

System.debug(cObj.Id+' '+cObj.firstName+' '+cObj.lastName);




e.g.:-

//This query will fetch all the record from the Contact object and those records

//will be represented as List of Contact sobject type

List<Contact> cList=[select firstName,lastName,Email from Contact];



//iterate over the list

for(Contact cObj:cList){

    System.debug(cObj.firstName+' '+cObj.lastName);

}


SOQL :- 

1. SOQL stands for Salesforce Object Query Language.

2. SOQL Query is used to fetch the data from the salesforce object or related objects.

3. SOQL is kind of similar with SQL with few differences.

4. SOQL query always start with SELECT keyword

5. Return type of SOQL query is List<SObject> type..

6. Maximum limit of SOQL is 20000 characters otherwise we will get Query_To_Compilated error.


Basic Syntax of SOQL query :-

select field1, field2, ... fieldn from ObjectName


In SOQL query ,we cant use * symbol.


Where I can write the SOQL query :-

1. Can be written inside the apex code :- always write the SOQL query in [] in apex code.

2. or can also be written inside the Query editor.


Note :- In SOQL query , we need to write the API name for the fields and the objects.


Lets start writing a simple SOQL Query inside the Query Editor:-


1. select Id,Name,Industry,Rating from Account 


This query will return all the record bcz we have not specified any criteria but it will fetch only from four fields which are Id, Name,Industry and Rating . In SOQL Query we cant use * to fetch the data from all the fields , Here we have to explicitly specify the name of the fields.


2. Lets write a simple query to fetch Id , firstName,LastName,email , phone from Contact


select Id,firstName,lastName,email,phone from Contact



where clause in SOQL :- where clause is used to fetch only those records are satisfying the given condition..

syntax :-

select field1,field2 from Object where condition



e.g. Lets write a simple query to fetch Id , firstName,LastName,email , phone of those contact where phone is not null


select Id,firstName,lastName,email,phone from Contact where Phone!=null


e.g. :- Lets write a simple query to fetch the details of those contacts where firstName is equal to Lakshay

select Id,firstName,lastName,email,phone from Contact where FirstName='Lakshay'


e.g. :- Lets write a simple query to fetch the details of those contacts where firstName is equal to Lakshay or John or Rose or Tim


select Id,firstName,lastName,email,phone from Contact where FirstName='Lakshay' or FirstNAme='John' or FirstNAme='Rose' or FirstName='Tim'


OR


select Id,firstName,lastName,email,phone from Contact where FirstName in ('Lakshay','John','Rose','Tim')


e.g. :- Lets write a query to display the Id,Name and ,website , Type of the hospital object..


select Id,Name,Website__c,Type__c from Hospital__c


Always keep in mind that in SOQL Queries , we have to write the API name of the fields and the objects..


e.g. :- Lets write a query to display the Id,Name and ,website , Type of the hospital object in the apex code.. 


List<Hospital__c> hospList=[select Id,Name,Website__c,Type__c from Hospital__c];

for(Hospital__c hObj:hospList){

    System.debug(hObj.Id+' '+hObj.Name+' '+hObj.Website__c+' '+hObj.Type__c);

}


e.g. :- anyway to know which fields are there in object from developer console?


Ans L- Go to developer console - Press Ctrl+Shift+O - specify the Object Name- select that..


e.g. :- Create a class named as SOQLDemo , In this class create a static method named as 

fetch accounts , in this method write a query to fetch the list of accounts and iterate over that...

public class SOQLDemo {

    public static void fetchEmployees(){

        List<Employee__c> emps=[select Name,Employee_Name__c,Email_Address__c,Designation__c from Employee__c];

        for(Employee__c emp:emps){

            System.debug(emp.Name+' '+emp.Employee_Name__c+' '+emp.Email_Address__c+' '+emp.Designation__c);

        }

    }

}


In anonymous window:- 

SOQLDemo.fetchEmployees();


e.g. Now there is a requirement that we need to fetch the details of only those employees whose designation is passed as the method argument..


public class SOQLDemo {

    public static void fetchEmployees(string desg){

        

        //Variable binding in SOQL Query inside apex.. At runtime This SOQL Query will fetch those records

        //where the value of Designation is equal to the value passed as the argument..

        List<Employee__c> emps=[select Name,Employee_Name__c,Email_Address__c,Designation__c from Employee__c

                               where Designation__c =:desg];

        for(Employee__c emp:emps){

            System.debug(emp.Name+' '+emp.Employee_Name__c+' '+emp.Email_Address__c+' '+emp.Designation__c);

        }

    }

}


anonymous window:-


SOQLDemo.fetchEmployees('Field Representative');


e.g. order by clause:- order by clause is used to arrange the data in ascending or descending order of a field..


select Name,Industry from Account order by Name


select Name,Industry from Account order by Name desc


select Name,Industry from Account order by Industry desc


e.g. :- limit clause - In the below query , limit clause will fetch the first 5 records..


select Name,Industry from Account limit 5


e.g. :- offset clause :-


select Name,Industry from Account order by Name limit 5 - This query will return the first 5 records..


select Name,Industry from Account order by Name limit 5 offset 6- This query will return the five records starting from the specified index ..


e.g. :- Sorting on the basis of date

select Name,Industry,createddate from Account order by createddate desc



e.g. :- what shud be the query if we want to fetch any particular index of record like record no. 5 of Account sObjects - 

select Name,Industry,createddate from Account limit 1 offset 5


e.g. Aggregate function :- In soql query , we can use aggregate functions like sum() , avg() , min() , max() and count()


select count(ID) From account


e.g. group by clause:-

Write a query to display the Lead source and Total no of leads coming from that particular leadsource..


select LeadSource , count(Id) From Lead group by Leadsource


e.g. group by with where clause:-

In the above we want to display only those records where leadsource is not null.


select LeadSource , count(Id) From Lead where leadsource!=null group by Leadsource


e.g. In the above query we want to display only those records where count is greater than 5


select LeadSource , count(Id) From Lead where leadsource!=null group by Leadsource having count(ID)>5


having will be used when we need to use aggregate functions in the criteria..


Relationship Queries :-

As of now, we have only fetched the data from a single object , Now we will learn how to fetch the data from related objects. There are two types of relationship queries which are as follows:-

a) Parent to Child SOQL Query (Inner Query)

b) Child To Parent SOQL Query..


Parent to Child SOQL Query :- Whenever we want to retrieve the child records for particular parent record or set of parent record then we will use the concept of inner query.. In simple words ,we can say we are writing the query of parent object and in that query we are fetching the details of related child records also..


e.g. Write the query to retrieve the Name , Industry of account with the related child contact records.


select Name,Industry,(select firstName,lastName from Contacts) from Account


e.g. Write the query to retrieve the Name , Industry of Edge communications account with the related child contact records.


select Name,Industry,(select firstName,lastName from Contacts) from Account where Name='Edge Communications'


Here , in the above query we have written contacts , here contacts is the relationship Name and for the standard objects relationship name will always be the plural label of Object Name. for custom objects , we will append __r with the relationship Name.


How to get the relationship Name:-

from the object Manager - Go to the child object - Click on Fields and relationship - Go to the relationship field - There u will get the relationship Name.


e.g. :- Lets write a query to display the Pharma Product NAme, Price , Product Type of Pharma Product object and also display the related sample records. 


select Product_Name__c, Price__c,Product_Type__c,(select Name from Samples__r) from Pharma_Product__c


Child To Parent Query :-  

Sometimes we want to fetch few fields of the parent record also while working with the child record then we will go for child to parent query..

for example :- while retrieving the data from the contact object , The user needs to known the Account shipping address from the account object..


select Id,FirstName,LAstName,Account.Name,Account.Industry,Account.ShippingAddress from contact


In the above SOQL Query  , account is the field Name for Look Up /Master detail relationship on the contact object . In custom object , we have to write field Name with the __r. To see the fieldName go to the object Maneger of the child Object . 



One more example of child to parent :- Lets write a query to display the Visit No , Visit Date and Hospital Name , Type of the hospital in which has been done.. Here Visit is the child object and hospital is the parent..


select Name,Visit_Date__C,Hospital__r.Name,Hospital__r.Type__c from Visit__c


Task :- 


1. Try to practice the relationship queries in apex code and iterate over the result .


SOSL :-


1. SOSL stands for Salesforce Object Search Language..

2. SOSL is used to perform text searches in records.

3. Use SOSL to search across multiple standard and custom objects records in the salesforce.

4. SOSL always start with Find

5. In query editor , we will write the search text in curly braces whereas in apex , we will write the search text in '' single quotes

6. Return type of SOSL query is List<List<SObject>>


Syntax of SOSL Query:-


find 'searchText' [IN SEARCH GROUP] [RETURNING OBJECTS And FIELDS]


Here , searchText is the text that we want to search . A search text can be a single word or it can be phrase i.e. collection of words.


search Group :- Here we need to specify the fields in which search needs to be performed . It is optional which means it is mandatory to specify the search group , if not specified then the search scope will be ALL Fields . Search group can take one of the following values:-

IN ALL FIELDS(by default)

IN NAME FIELDS

IN EMAIL FIELDS

IN PHONE FIELDS


RETURNING OBJECTS And FIELDS:-

1. It is optional to specify

2. It is the information to return in the search result . If not specified then the search result will contains the IDS of the all the object in which my text is found..



e.g. 1:-


FIND {University}




In the above example , we want to find University Text , by default it will be searched in all the fields for all the contacts and will return the IDs of those records for all the objects in which searchTExt University is found..


e.g. 2:- 

FIND {University} RETURNING ACCOUNT(ID,Name) , OPPORTUNITY(ID,NAME)


This query will search University in all the fields for all the objects and will return the ID and NAme for the Account and Opportunity object is given text is found..


e.g. 3:- 

FIND {University} IN NAME FIELDS RETURNING ACCOUNT(ID,Name) , OPPORTUNITY(ID,NAME)


e.g. 4:-

FIND {.gmail.com} IN EMAIL FIELDS RETURNING EMPLOYEE__C(ID,NAME,EMAIL_ADDRESS__C)


e.g. 5:-

FIND {Uni} IN NAME FIELDS RETURNING ACCOUNT(ID,NAME)


Q :- Write the apex code to search for the University text in all the objects and return ID and Name of the Opportunity and account..


Ans:- 




List<List<SObject>> soslList=[FIND 'University' IN ALL FIELDS RETURNING 

                              ACCOUNT(ID,NAME),OPPORTUNITY(Id,Name)];


for(List<SObject> l:soslList){

for(SObject sObj:l){

//SObject is the generic type , I cant access the specific properties of //any specific sobject type. so i need to downcast it..

if(sObj instanceof Account){

Account acc=(Account)sObj;

System.debug(acc.Name);

}

else if(sObj instanceof Opportunity){

Opportunity opp=(Opportunity)sObj;

System.debug(opp.Name);

}

}

}



can we  access specific  value using list index :- Here in our

scenario we have to access the object from the list , downcast to specific type and can access it property..


Difference b/w SOQL and SOSL :-

SOQL SOSL 


1. SOQL starts with select    1. starts with FIND

2. SOQL will be used when    2. SOSL will search in all the standard

we are aware in which specific  or    and custom objects

relared objects

we wants to query for the data

3. The return type of SOQL is   3. The return type of SOSL is 

list<SObject>   List<List<sObject>>


Note :_ SOQL And SOSL both are used to query the data..


Governor limits:=


1. Total number of SOQL queries issued -100 in synchronous apex and 200 in asynchronous apex.

2.Total number of records retrieved by SOQL queries - 50000

3. Total number of SOSL queries issued -20

4. Total number of records retrieved by a single SOSL query- 2000


AS we have seen SOQL And SOSL both are used to query or to find the data . SOQL And SOSL both cant perform any kind of Data Manipulation. Apex has provided us some DML statement to perform dml operations..


DML Statements:-

1. Apex enables you to insert , update , delete or restore the data in the database using DML Statements.

2. DML statements allow you to modify records once at a time or in batches . Performing bulk DML operation is the recommended way bcz it helps in avoiding hitting governor limits such as the DML limit of 150 statements per transaction.


152 records at a time:-

insert rec1;

insert rec2: - 152 times (will give u error of hitting governor limits)


We can store all the records in a single and can perform DML on that list

insert myList; --(Will be counted as 1 DML statement.)



3. Another DML governor limit is the total no. of records that can be processed by a single DML operation in a single transaction which is 10,000.


insert statement :- insert statement as the name says is used to insert a record into the salesforce org..


e.g. of Inserting one record at a time...

Account acc=new Account(Name='Test account 5 October',Industry='Banking');

acc.rating='Hot';


//As soon as we will insert a record , the record will be generated by salesforce

//which can be accessed like below :- acc.Id

insert acc;


System.debug('Account with record Id '+acc.Id+' inserted succesfully...');


e.g. of Inserting a List:-


List<Account> accList=new List<Account>{

    new Account(name='Test Acc 1'),

            new Account(name='Test Acc 2'),

            new Account(name='Test Acc 3')

    

};

    

insert accList;


update statement :-

----------------



Account acc=[select Name,Industry from 

             Account where Name='Test Account 5 October' limit 1];

System.debug('Account Name before Update : '+acc.Name);

System.debug('Account Industry Before Update : '+acc.Industry);


//Lets update the fields now..

acc.Name='Account of the day';

acc.Industry='Technology';


update acc;


//Now lets write the query again to get the updated result..

acc=[select Name,Industry from 

             Account where Name='Account of the day' limit 1];

System.debug('Account Name after Update : '+acc.Name);

System.debug('Account Industry after Update : '+acc.Industry);


Ex:- Write a class named as DML Demo  which has a static method named as updateContacts which will update the phone field of all the related contacts with the phone field of the account whose name has been passed in the method argument.


public class DMLDemo {

public static void updateContacts(String accountName){

        List<Account> accList=[select Id,Name,Phone,(select Id,Name,Phone from contacts) from Account 

                               where Name =:accountName];

         List<Contact> contactsList=new List<Contact>();

            for(Account acc:accList){

                List<Contact> cList=acc.contacts;

                for(Contact c:cList){

                    c.phone=acc.phone; 

                    contactsList.add(c);

                }

            }

         update contactsList;

    }

}


In anonymous window:-


DMLDemo.updateContacts('Genepoint')


Delete statement :-

-----------------

After you persist the records in the database , you can delete the records using the delete operation. Deleted records are not permanently deleted from the salesforce , they are placed in the recycle bin for 15 days from where they can be restored.


Account[] accList=[select Id from Account where createddate=today];

delete accList;

System.debug('Records deleted succesfully..');


Restoring deleted records (Undelete statements):-

----------------------------------------------

After you have deleted records , the records can be restored within 15 days from the recycle bin..



Account[] accList=[select Id from Account where createddate=today ALL ROWS];

undelete accList;

System.debug('REcords restored succesfully...');


Upserting Records :-

Using the upsert statement , you can either insert or update an existing record in one call . To determine whether a record already exist the upsert statement uses the record Id as the key to match a record or can use a external ID field also.


1. If the record Id or the given external ID is matched , then a existing record will be updated otherwise new record will be created..



//Here I have created a new sobject so it wont be having the record Id bcz record Id will

//be generated by salesforce when record will gets inserted only..

Account newAcct=new Account(name='Acme',BillingCity='San francisco');


//This query will return one record whre billing city is Chicago. That record obviously will

//be having record Id bcz it is coming from salesforce org..

Account[] accList=[select Id,Name,Phone,billingCity from Account where billingcity='Chicago'];

for(Account acc:accList){

    acc.BillingCity='Mumbai';

}


accList.add(newAcct);  


//Here , my list is having two records , for first sobject recordId is not there so

//it will be inserted whereas in the second record , recordId so it will be updated..

upsert accList;  



Note :- It is not mandatory to specify the Id in the select query . It will be returned by default...



try {

Contact cObj=new Contact(firstName='Ramamoorthy');

insert cObj;

}

catch(DMLException e){

    System.debug(e);

}


Task :- Perform the upsert on the basis of external Id..


Tomorrow's Agenda :-

1. Database class methods

2. Visualforce





Using DML statements whenever we are trying to manipulate

a list of records and if any one of the record is giving the exception , the complete transaction will be rolled back or we can say DML statements will do partial insert or update . Either will manipulate the complete list or wont manipulate any record..


List<Contact> conList=new List<Contact>{

new Contact(FirstName='Swati',LastName='Sehgal'),

new Contact(FirstName='ABC',LastName='Singh'),

new Contact(FirstName='ABC')

};


insert conList;


If we want to perform partial DML then we need to the methods of Database.

e.g. 



List<Contact> conList=new List<Contact>{

new Contact(FirstName='Swati',LastName='Sehgal'),

new Contact(FirstName='ABC',LastName='Singh'),

new Contact(FirstName='ABC')

};


//Passing false as the second argument means we want

//to perform partial DML .

List<Database.SaveResult> results=Database.insert(conList,false);

for(Database.SaveResult res:results){

    /*isSuccess is the method of Database.SaveResult class*/

    if(res.isSuccess()){

        System.debug('Record with Id '+res.getId()+' inserted succesfully');

    }

    else {

        //getErrors() is the method of Database.SaveResult which will return

        //list of all errors which are responsible to fail this DML.

        List<Database.Error> errors=res.getErrors();

        for(Database.Error err:errors){

            //getFields and getMessage() are the method of Database.Error 

            //class

            System.debug(err.getFields()+' '+err.getMessage());

        }

    }

}


e.g. 2:-

//Lets say there is a requirement to insert a record of Opportunity type and I want 

//to display the success msg if record is inserted otherwise I Want to display the 

//cause of the error - 

//Tell me what to use insert DML statement or insert method of Database class.


Opportunity opp=new Opportunity(Name='Wipro Opp');

opp.stageName='Prospecting';

opp.closeDate=system.today()+30;

/*If we wont pass false as the second argument in the methods of Database class then 

they will become equivalent to DML statements which will generate the exception 

if record cant be manipulated (inserted in our case) and code will be terminated..

wont go to the next line.... */

Database.SaveResult res=Database.insert(opp,false); 

if(res.isSuccess()){

    System.debug('Opportunity inserted Succesfully..');

}

else {

    List<Database.Error> errs=res.getErrors();

    for(Database.Error err:errs){

        System.debug(err.getFields());

        System.debug(err.getMessage());

    }

}



e.g. :-


//This query will return all the accounts from the salesforce org

List<Account> accts=[select Id from Account];


/*Here either all the accounts will be deleted or none of the account will get deleted.

If there is any issue in deleting any one of the account then the delete statement

will throw the DMLException*/

//delete accts; 


//Lets try to delete with delete method of Database class.

//Database.delete(accts);   //This is equivaent to delete DML statement . Bcz here 

//we havent false in the second argument . This will throw the DMLException


List<Database.DeleteResult> results=Database.delete(accts,false); //Here the accounts which cant be deleted will be deleted .

for(Database.DeleteResult res:results){

    if(res.isSuccess()){

        System.debug('Record deleted succesfully');

    }

    else {

        List<Database.Error> errs=res.getErrors();

        for(Database.Error err:errs){

            System.debug(err.getMessage());

        }

    }

}


Visualforce Framework :-


1. Visualforce framework is used to create custom User interfaces in Salesforce.

2. Through Visualforce framework we can customized or extend or we can also replace the existing User interface provided by salesforce.

3. Visualforce framework consist of two things :-

a) Visualforce Page.

b) Controller 

Visualforce page will consist of mark ups like Html which will be in angle brackets like

<apex:page>

<apex:pageBlock>

Every tag of VF page will be enclosed in angle brackets and every tag which is known as component in VF terminology must be having the end tag like..

</apex:page> - end tag of <apex:page>


Every tag or component will have attribute to provide additional information to the components.

<apex:pageBlock title="Demo">

Here title is the attribute and Demo is the value of that attribute . The attribute value will always come in double quotes...

Controller :- Controller is the apex class where we will write the business logic . E.g. we will create a button in VF Page and what happens when someone clicks on that button we will write in controller.


There are four types of controllers:-

1. Standard Controller

2. Standard List Controller

3. Custom Controller

4. Controller Extension



Lets create the First VF Page :-

------------------------------


e.g. 1:- 

<apex:page >

    <apex:pageBlock title="Introduction to Visualforce Page">

       <apex:pageBlockSection title="My First VF Demo">

           <h1 style="color:green;font-size:30px">Hello How r u all?</h1>

       </apex:pageBlockSection>   

       <apex:pageBlockSection title="My Second VF Demo">

           <h1 style="color:green;font-size:30px">{!2*3}</h1><br/>

           <h1 style="color:green;font-size:30px">{!today()}</h1><br/>

           <h1 style="color:green;font-size:30px">{!$User.userName}</h1><br/>

           <h1 style="color:green;font-size:30px">{!$User.firstName}</h1><br/>

           <h1 style="color:green;font-size:30px">{!$User.lastName}</h1><br/>

       </apex:pageBlockSection>

    </apex:pageBlock>

</apex:page>


e.g. 2:- There are two ways to create a VF Page:-

1. USing Developer console.

2. Using Inbuilt editor of VF Page , for that 

Go to settings - Advance User Details- Edit - check development mode - click 

on save.. Now to create VF Page , in the URL Of salesforce org after force.com/apex/NameoftheVF Page..


<apex:page >

  <h1>Congratulations</h1>

  This is your new Page: VF2 by Inbuilt editor

  

</apex:page>


e.g. 3 - Showing the use of Custom Controller :-

------------------------------------------------


1. Custom controller is nothing , it is an apex class with non-paramterised constructor.

2. A VF Page cant access the variables of the controller , they can only access the public methods of controllers . To get the value from the controller to the VF Page we need to create getter method and to set the value from the VF Page to the controller we need to create the setter method..


public class CustomCtrl1 {

    //This is a variable of controller class but we know VF Page cant access the variables of controller.

     String greeting='Hello All , How r u ?? how ur training is going on';

    

    

    //To access the data from controller to VF we need to create the getter method-

    /*

     * getter method needs to be public , now bcz we are creating the getter method for String type of variable so return type

     * of the method will obviously be string , bcz it is a getter method of greeting variable so according to naming convention

     * the name of the method should be getGreeting

*/

    public String getGreeting(){

        return greeting;

    }

    

    List<String> fruitsList=new List<String>{

      'Apple','Mango','Banana','Papaya','Pineapple'  

    };

        

    //getter method

    public List<String> getFruits(){

            return fruitsList;

    }    

    

}


<apex:page controller="CustomCtrl1">

    <apex:pageBlock title="Custom Controller">

        <apex:pageBlockSection title="Greeting Msg">

            {!greeting} <!--Here by default it will call getGreeting method to get the data from controller to VF-->

        </apex:pageBlockSection>

        <apex:pageBlockSection title="Accessing Fruit List" columns="1">

            <!--{!fruits} Here by default getFruits method will be called-->

            

            <ul>

            <apex:repeat value="{!fruits}" var="fr">

                <li>{!fr}</li>

            </apex:repeat>

            </ul>

        </apex:pageBlockSection>

    </apex:pageBlock>

</apex:page>


e.g. :-

<apex:page controller="VF4Ctrl">

    <apex:pageBlock title="Setter Getter Demo">

        <apex:pageBlockSection title="My Form">

            <apex:form>

                <table>

                    <!--Here setFirstName  and setLastName method will be called to set the value from text fields to the

controller-->

                   <tr>

                       <td>First Name</td>

                       <td><apex:inputText value="{!firstName}"/></td>

                   </tr> 

                    <tr>

                        <td>Last Name</td>

                        <td><apex:inputText value="{!lastName}"/></td>

                    </tr>

                    <tr>

                        <td colspan="2">

                            <!--On click of this button getFullName method will be called-->

                <apex:commandButton action="{!performConcat}" value="Get Full Name"/>

                        </td>

                    </tr>

                    <tr>

                        <td colspan="2">

                             <!--Here getFullName method will be called to get the value

from the controller to the VF Page-->

                <apex:outputText value="{!fullName}"/>

                        </td>

                    </tr>

                </table>

                 

            </apex:form>

        </apex:pageBlockSection>

    </apex:pageBlock>

</apex:page>


public class VF4Ctrl {

    

    public String firstName{get; set;}

    public String lastName{get; set;}

    public String fullName{get; set;}

    

    

    public void performConcat(){

        fullName=firstName+' '+lastName;

        

    }

    

}



Ex-1 :- Write a VF page to display the list of all the Accounts.. (CRUD)


- Let me show how to create a Tab for the VF PAge..


public class CustomCtrl_1 {


    public Account acc{get; set;}

    public List<Account> accountsList{get; set;}

    public Id accountId{get; set;}

    

    //It is mandatory for a customcontroller to have non-parameterised constructor

    public CustomCtrl_1(){

        acc=new Account();

        accountsList=[select Name,Industry,Rating,AnnualRevenue from Account];

    }

    public PageReference addAccount(){

        Database.UpsertResult res=Database.upsert(acc,false);

        if(res.isSuccess()){

          /*  ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,'Account Added or Updated Succesfully..'));

            accountsList.add(acc);*/

            

            //Here if account is inserted or updated we want to redirect to the Record Detail PAge..

            PageReference pRef=new PageReference('/'+acc.Id);

            return pRef;

            

            //PageReference can be used to redirect to any other VF Page also...

        }

        else {

            Database.Error[] errs=res.getErrors();

            for(Database.Error err:errs){

                ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR,err.getMessage()));

                

            }

            return null;  //returning null will stay on the same page...

        }

    }

    public void deleteAccount(){

        Account acc1=[select Id from Account where Id=:accountId];

        Database.DeleteResult res=Database.delete(acc1,false);

        if(res.isSuccess()){

            ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,'Account deleted Succesfully'));

            accountsList.clear();

            accountsList=[select Name,Industry,Rating,AnnualRevenue from Account];

        }

        else {

            Database.Error[] errs=res.getErrors();

            for(Database.Error err:errs){

                ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR,err.getMessage()));

                

            }

        }

        

    }

    public void editAccount(){

        acc=[select Id,Name,Industry,AnnualRevenue,Rating from Account where Id=:accountId];

       

        

    }

}


<apex:page controller="CustomCtrl_1">

    <apex:pageBlock title="Account CRUD">

        

       

        <apex:pageMessages></apex:pageMessages>

        <apex:pageBlockSection>

                   <apex:form>

                   <table>

                      <tr>

                           <td>Account Name :</td>

                           <td><apex:inputField value="{!acc.Name}"/><br/></td>

                       </tr>

                       <tr>

                           <td> Industry : </td>

                           <td><apex:inputField value="{!acc.Industry}"/><br/></td>

                       </tr>

                       <tr>

                           <td>Rating : </td>

                           <td><apex:inputField value="{!acc.Rating}"/><br/></td>

                       </tr>

                       <tr>

                           <td>Annual Revenue :</td>

                           <td><apex:inputField value="{!acc.AnnualRevenue}"/><br/></td>

                       </tr>

                       <tr>

                           <td colspan="2">

                               <apex:commandButton value="Add Account" action="{!addAccount}"/>

                           </td>

                       </tr>

                   </table>

                  

                </apex:form>          

        </apex:pageBlockSection>

        <br/>

        

        <apex:form>

            <apex:pageBlockTable value="{!accountsList}" var="acc">

                <apex:column value="{!acc.Name}" headerValue="My Account Name"/>

                <apex:column value="{!acc.Industry}"/>

                <apex:column value="{!acc.Rating}"/>

                <apex:column value="{!acc.AnnualRevenue}"/>

                <apex:column>

                   <apex:commandLink value="Edit" action="{!editAccount}">

                        <apex:param name="accId" value="{!acc.Id}" assignTo="{!accountId}"/>

                    </apex:commandLink>

                </apex:column>

                <apex:column>

                    <apex:commandLink value="Delete" action="{!deleteAccount}">

                        <apex:param name="accId" value="{!acc.Id}" assignTo="{!accountId}"/>

                    </apex:commandLink>

                </apex:column>

                 

            </apex:pageBlockTable>

        </apex:form>

    </apex:pageBlock>

</apex:page>


e.g. :- Search Tool


<apex:page controller="SearchCtrl">

    <apex:pageBlock title="Search Tool">

        <apex:form>

            <h1 style="color:red;font-size:30px">Enter the account name that you want to search...</h1><br/>

        <apex:inputText value="{!searchText}">

            <apex:actionSupport event="onkeyup" action="{!performSearch}" reRender="myList"/>

        </apex:inputText>

        

        </apex:form>

        

        <apex:pageBlockTable value="{!accounts}" var="acc" id="myList">

            <apex:column  value="{!acc.NAme}"/>

            <apex:column  value="{!acc.Industry}"/>

            <apex:column  value="{!acc.Rating}"/>

        </apex:pageBlockTable>

        

    </apex:pageBlock>

</apex:page>


public class SearchCtrl {

    public String searchText{get; set;}

    public Account[] accounts{get; set;}

    

    public void performSearch(){

        String search='%'+searchText+'%';

        accounts=[select ID,NAme,Industry,Rating from Account where Name like :search ];

    }

}


We have completed the Custom Controller as per our requirement for exam . Now lets see the concept of StandardController..


Standard Controller :- Standard Controller as the name suggest it is a  predefined controller providing the pre-defined functionality for all the standard and the custom objects . Standard Controller will work for the single record of an object ..


e.g. 1:- 


<apex:page standardController="Hospital__c">

    <apex:pageBlock title="Standard Controller">

        <apex:pageBlockSection title="Hospital Record">

            <apex:outputField value="{!Hospital__c.Name}"/>

            <apex:outputField value="{!Hospital__c.Phone__c}"/>

            <apex:outputField value="{!Hospital__c.Website__c}"/>

            <apex:outputField value="{!Hospital__c.City__c}"/>

            <apex:outputField value="{!Hospital__c.State__c}"/>

            <apex:outputField value="{!Hospital__c.Type__c}"/>

        </apex:pageBlockSection>

    </apex:pageBlock>

</apex:page>


In the URL:- To see the Hospital record , we need to pass the record Id in the URL..

https://c.ap16.visual.force.com/apex/StdCtrlDemo1?Id=a022w00000F6W6KAAV


Now , lets show this VF Page as the record detail page of the Hospital object.. Lets go the record detail page of the Hospital object - edit the page - Delete the existing things gettings display and show ur VF Page



but before this you need to make your VF page available for the lightning experience...

Quick Find - Visualforce page- edit ur Vf page -check enable for lightning



eg. 2:-

<apex:page standardController="Hospital__c">

    <apex:form>

    <apex:pageBlock title="Standard Controller">

        <apex:pageBlockSection title="Hospital Record">

            <apex:inputField value="{!Hospital__c.Name}"/>

            <apex:inputField value="{!Hospital__c.Phone__c}"/>

            <apex:inputField value="{!Hospital__c.Website__c}"/>

            <apex:inputField value="{!Hospital__c.City__c}"/>

            <apex:inputField value="{!Hospital__c.State__c}"/>

            <apex:inputField value="{!Hospital__c.Type__c}"/>

</apex:pageBlockSection>

<apex:pageBlockButtons>

            <!--The functionality of save and quick Save is the standard functionality-->

            <apex:commandButton value="Save" action="{!Save}"/>

            <apex:commandButton value="Quick Save" action="{!QuickSave}"/>

            </apex:pageBlockButtons>

    </apex:pageBlock>

    </apex:form>    

</apex:page>


Standard Controller :-


1. Standard Controller is the built in controller provided 

for all the custom and standard objects.

2. Standard Controller can work with one single record at a time according on the record Id.


Ex:- 


<apex:page standardController="Account">

    <apex:pageBlock title="Standard Controller Demo">

        <apex:pageBlockSection title="Account Info">

            <apex:outputField value="{!account.Name}"/>

            <apex:outputField value="{!account.Industry}"/>

            <apex:outputField value="{!account.Rating}"/>

            <apex:outputField value="{!account.Phone}"/>

        </apex:pageBlockSection>

        <apex:pageBlockSection title="Related Contacts">

            <apex:relatedList list="contacts"/>

        </apex:pageBlockSection>

        <apex:pageBlockSection title="Related Opportunities">

            <apex:relatedList list="opportunities"/>

        </apex:pageBlockSection>

        <apex:pageBlockSection title="Related Cases">

            <apex:relatedList list="cases"/>

        </apex:pageBlockSection>

    </apex:pageBlock>

</apex:page>


ex2:- 


<apex:page standardController="Account">

    <apex:pageBlock title="Standard Controller Demo">

        <apex:pageBlockSection title="Account Info">

            <apex:outputField value="{!account.Name}"/>

            <apex:outputField value="{!account.Industry}"/>

            <apex:outputField value="{!account.Rating}"/>

            <apex:outputField value="{!account.Phone}"/>

        </apex:pageBlockSection>

        <apex:pageBlockSection title="Related Contacts">

            <apex:pageBlockTable value="{!account.contacts}" var="cObj">

                <apex:column value="{!cObj.Name}"/>

                <apex:column value="{!cObj.Email}"/>

                <apex:column value="{!cObj.Phone}"/>

            </apex:pageBlockTable>

        </apex:pageBlockSection>

       

    </apex:pageBlock>

</apex:page>


ex 3:- <apex:page standardController="Account">

    <apex:form >

    <apex:pageBlock title="Standard Controller Demo">

        <apex:pageBlockSection title="Add or Edit Account">

            <apex:inputField value="{!account.Name}"/>

            <apex:inputField value="{!account.Industry}"/>

            <apex:inputField value="{!account.Rating}"/>

            <apex:inputField value="{!account.Phone}"/>

        </apex:pageBlockSection>

        <apex:pageBlockButtons >

            <!--HEre Save action will perform upsert , if record Id will be there will update the record otherwise will create a new record -->

            <apex:commandButton value="Save" action="{!Save}"/>

            <apex:commandButton value="QuickSave" action="{!Save}"/>

        </apex:pageBlockButtons>

        

    </apex:pageBlock>

    </apex:form>

</apex:page>


e.g. 4:-

<apex:page standardController="Account">

    <apex:pageBlock title="Standard Controller Demo">

        <apex:pageBlockSection title="Account Info">

            <apex:outputField value="{!account.Name}"/>

            <apex:outputField value="{!account.Industry}"/>

            <apex:outputField value="{!account.Rating}"/>

            <apex:outputField value="{!account.Phone}"/>

        </apex:pageBlockSection>

        <apex:pageBlockSection title="Related Contacts">

            <apex:pageBlockTable value="{!account.contacts}" var="cObj">

                <apex:column value="{!cObj.Name}"/>

                <apex:column value="{!cObj.Email}"/>

                <apex:column value="{!cObj.Phone}"/>

                <apex:column >

                    <apex:outputLink value="{!URLFOR($Action.Contact.Edit,cObj.Id)}">Edit</apex:outputLink>

                </apex:column>

                <apex:column >

                    <apex:outputLink value="{!URLFOR($Action.Contact.Delete,cObj.Id)}">Delete</apex:outputLink>

                </apex:column>

            </apex:pageBlockTable>

        </apex:pageBlockSection>

       

    </apex:pageBlock>

</apex:page>


StandardListController:-

1. The Standard List controller allows you to create VF pages that can display or act on a set of records.

2. It provides many powerful features such as filtering and pagination of records other than the standard actions such as Save , Quick Save , Edit and Delete

3. Standard controller will by default display 20 records on a page..


e.g. 1:-


<apex:page standardController="Account" recordSetVar="accounts" renderAs="pdf">

    <apex:pageBlock title="Standard List Controller">

            <apex:pageBlockTable value="{!accounts}" var="aObj">

                <apex:column value="{!aObj.NAme}"/>

                <apex:column value="{!aObj.Industry}"/>

                <apex:column value="{!aObj.Rating}"/>

                <apex:column value="{!aObj.AnnualRevenue}"/>

                <apex:column value="{!aObj.Phone}"/>

                <apex:column value="{!aObj.Website}"/>

            </apex:pageBlockTable>

     </apex:pageBlock>

</apex:page>


e.g. 2:-


<apex:page standardController="Contact" recordSetVar="contacts">

    <apex:form >

    <apex:pageBlock title="Standard List Controller">


            <apex:selectList value="{!filterId}" size="1">

                <apex:selectOptions value="{!listViewOptions}"/>

                <apex:actionSupport event="onchange" reRender="myList"/>

            </apex:selectList>

            


            <apex:pageBlockTable value="{!contacts}" var="cObj" id="myList">

                <apex:column value="{!cObj.NAme}"/>

                <apex:column value="{!cObj.Title}"/>

                <apex:column value="{!cObj.Phone}"/>

                <apex:column value="{!cObj.Email}"/>

                <apex:column value="{!cObj.Account.Name}"/>

            </apex:pageBlockTable>

            <apex:pageBlockButtons >

                <apex:commandButton value="First" action="{!first}" disabled="{!NOT(hasPrevious)}"/>

                <apex:commandButton value="Next" action="{!next}" disabled="{!NOT(hasNext)}"/>

                <apex:commandButton value="Previous" action="{!previous}" disabled="{!NOT(hasPrevious)}"/>

                <apex:commandButton value="Last" action="{!last}" disabled="{!NOT(hasNext)}"/>

            </apex:pageBlockButtons>

     </apex:pageBlock>

     </apex:form>

</apex:page>


e.g. 3:-

<apex:page standardController="Contact" recordSetVar="contacts">

    <apex:form >

    <apex:pageBlock title="Standard List Controller">


            <apex:selectList value="{!filterId}" size="1">

                <apex:selectOptions value="{!listViewOptions}"/>

                <apex:actionSupport event="onchange" reRender="myList"/>

            </apex:selectList>

            


            <apex:pageBlockTable value="{!contacts}" var="cObj" id="myList">

                <apex:column headerValue="First Name">

                    <apex:inputField value="{!cObj.FirstName}"/>

                </apex:column>

                <apex:column headerValue="Last Name">

                    <apex:inputField value="{!cObj.LastName}"/>

                </apex:column>

                <apex:column headerValue="Title">

                    <apex:inputField value="{!cObj.Title}"/>

                </apex:column>

                <apex:column headerValue="Phone">

                    <apex:inputField value="{!cObj.Phone}"/>

                </apex:column>

                <apex:column headerValue="Email">

                    <apex:inputField value="{!cObj.Email}"/>

                </apex:column>

                <apex:column headerValue="Account Name">

                    <apex:inputField value="{!cObj.Account.Name}"/>

                </apex:column>

                

            </apex:pageBlockTable>

            <apex:pageBlockButtons >

                <apex:commandButton value="First" action="{!first}" disabled="{!NOT(hasPrevious)}"/>

                <apex:commandButton value="Next" action="{!next}" disabled="{!NOT(hasNext)}"/>

                <apex:commandButton value="Previous" action="{!previous}" disabled="{!NOT(hasPrevious)}"/>

                <apex:commandButton value="Last" action="{!last}" disabled="{!NOT(hasNext)}"/>

                <apex:commandButton value="Quick Save" action="{!quickSave}"/>

            </apex:pageBlockButtons>

     </apex:pageBlock>

     </apex:form>

</apex:page>


Controller Extension:-

1. A controller extension is a controller which can extend the functionality provided by some existing controller which can be standard controller , standard list controller or custom controller.

2. A controller extension is any apex class containing a constructor that takes a single argument or type ApexPages.StandardController or Custom Controller Name depending which controller you want to extend.


public class MyControllerExtension {

    private Account acct;

    

    public MyControllerExtension(ApexPages.StandardController stdController){

       acct=(Account)stdController.getRecord();

    }

    public String getMsg(){

        

        //Here in the greeting I want to fetch the account name as well...

        return 'Welcome  '+UserInfo.getFirstName()+' '+UserInfo.getLastName()+' to account '+acct.Name;

    }

    

}


<apex:page standardController="Account" extensions="MyControllerExtension">

    <apex:Form>

        <apex:pageBlock>

            <apex:pageBlockSection columns="1">

                <h1>

                    {!msg}  <!--Here by default getGreeting will be called to access

the data from controller to VF-->

                </h1>

                <p/>

        <apex:inputField value="{!account.NAme}"/>

        <apex:commandButton value="Save" action="{!save}"/>

            </apex:pageBlockSection>

        </apex:pageBlock>

    </apex:Form>

</apex:page>


e.g. :-


<apex:page standardController="Account" extensions="MyControllerExtension">

    <apex:pageMessages/>

    <apex:Form>

        <apex:pageBlock>

            <apex:pageBlockSection columns="1">

               <apex:inputField value="{!account.NAme}"/>

        <apex:commandButton value="Save" action="{!save}"/>

            </apex:pageBlockSection>

        </apex:pageBlock>

    </apex:Form>

</apex:page>


public class MyControllerExtension {

    private Account acct;

    

    public MyControllerExtension(ApexPages.StandardController stdController){

       acct=(Account)stdController.getRecord();

    }

    public void save(){

        insert(Acct);

        ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO,'Account Added or Updated Succesfully..'));

    }

    

}



Wrapper class:- (Wont come in the exam) :-

-----------------------------------------


public class SearchCtrl {

    public String searchText{get; set;}

    public MyWrapper[] wrapList{get; set;}

    

    public void performSearch(){

        String search='%'+searchText+'%';

        Account[] accounts=[select ID,NAme,Industry,Rating from Account where Name like :search ];

        

        wrapList=new List<MyWrapper>();

        for(Account acc:accounts){

            wrapList.add(new MyWrapper(acc));

        }

    }

    

    public class MyWrapper {

        public Account accObj{get; set;}

        public boolean isChecked{get; set;}

        

        public MyWrapper(Account accObj){

            this.accObj=accObj;

            isChecked=false;

        }

    }

    public void deleteAccounts(){

        List<Account> accLi=new List<Account>();

         for(MyWrapper w:wrapList){

             if(w.isChecked==true){

                 accLi.add(w.accObj);

             }

        }

        delete accLi;

    }

}



<apex:page controller="SearchCtrl">

      <apex:form>

    <apex:pageBlock title="Search Tool">

        

            <h1 style="color:red;font-size:30px">Enter the account name that you want to search...</h1><br/>

        <apex:inputText value="{!searchText}">

            <apex:actionSupport event="onkeyup" action="{!performSearch}" reRender="myList"/>

        </apex:inputText>

        

        

        <apex:commandButton value="Delete Accounts" action="{!deleteAccounts}"/>

    

        <apex:pageBlockTable value="{!wrapList}" var="wObj" id="myList">

            

            <apex:column headerValue="Select">

                <apex:inputCheckbox value="{!wObj.isChecked}"/>

            </apex:column>

             

            <apex:column value="{!wObj.accObj.NAme}"/>

            <apex:column value="{!wObj.accObj.Industry}"/>

            <apex:column value="{!wObj.accObj.Rating}"/>

            

               

        </apex:pageBlockTable>

        

     </apex:pageBlock>

</apex:form>

         

</apex:page>





Triggers :-


Trigger is a piece of code which is used to automate some task on the occurence of a DML operation..


e.g. We can write a trigger to send a email to the Contact as soon as the Contact gets inserted . This can be achieved by using Trigger.



There are two types of triggers:-


1. Before trigger :- These before triggers are fired before the DML operation gets effected.Validation kind of task can be done in before trigger.


2. After trigger :-These after triggers are fired after the DML operation gets effected.

In situation where we need to system generated fields like created date , created by or record ID we will be using after trigger.


Trigger Events :- These are the events for which trigger will be fired:-

1. Before insert

2. after insert

3. before update

4. after update

5. before delete

6. after delete

7. after undelete


Context Variables of Trigger :-Context variables of trigger which help us to fetch the data on which dml has been fired and context variables of trigger are also used to access information related to the event on which trigger has been fired:-

1. Trigger.NEw :- Trigger.NEw is a context variable that will return the list of those records on which DML has been fired..

2. Trigger.Old

3. Trigger.NewMap :- Trigger.NEw will return the map of new version of records where key is the record and value is the record itself..

4. Trigger.oldMap

5. Trigger.isBefore

6. Trigger.isAfter

7.Trigger.isInsert

8.Trigger.isUpdate

9. Trigger.isDelete

10. Trigger.Undelete


Syntax of Trigger


Trigger NameOFTrigger on ObjectName(event){

}



Before Insert Trigger :-


1. In the before insert trigger we cant use context variables like Trigger.Old , Trigger.OldMap and Trigger.New .

2. In the before insert trigger , the new records we are trying to insert cant be fetched using the SOQL query.

3.If you want to modify the records which are in Trigger.New , we can do that in before insert trigger 



Ex :- Whenever new account is created with industry as Banking  then 

set value of Ownership  fields as private.


Ans:-

trigger AccountTrg on Account (before insert) {


    /* Here I need to access the account record which is getting inserted and I need to check the Industry field of that

      account.*/

    

    /*Trigger.New is a context variables that will return the list of all those records on which insert DML 

has been performed.*/

    List<Account> accs=Trigger.New;  

    for(Account acc:accs){

        if(acc.Industry=='Banking'){

            acc.Ownership='Public';

        }

    }

}



Ex 2:- Whenever a new Contact is inserted without Account then throw a error.

Ans:- 


trigger contactTrg on Contact (before insert) {

    

    List<Contact> contactList=Trigger.New;

    for(Contact con:contactList){

        if(con.accountId==null){

            con.addError('Contact must be associated with some account');

        }

    }


}


After Insert :-

1.If you want to modify the records which are there in Trigger.New you need to write DML operation

2. In the after insert trigger , new records can be fetched using SOQL Query.


Ex:- Whenever a new account is created with Industry as Education and Rating as Warm , Then create new child opportunity with opportunity name as account name , Type as NEw Customer , close date as today date+30 days , stage as prospecting


trigger AccountTrg on Account (before insert,after insert) {


    if(Trigger.isBefore && Trigger.isInsert){

    List<Account> accs=Trigger.New;  

    for(Account acc:accs){

        if(acc.Industry=='Banking'){

            acc.Ownership='Public';

        }

    }

    }

    else if(Trigger.isAfter && Trigger.isInsert){

        List<Opportunity> oppList=new List<Opportunity>();

        List<Account> accList=Trigger.New;

        for(Account acc:accList){

            if(acc.Industry=='Education' && acc.Rating=='Warm'){

                Opportunity opp=new Opportunity(name=acc.Name,Type='New Customer',stageName='prospecting',

                                                closeDate=system.today()+30);

                opp.accountId=acc.Id;

                oppList.add(opp);

             }

        }

        insert oppList;

    }

}


Before Update Trigger :-

--------------------------


Ex 1:- Whenever industry is changing to banking then update the phone number as 8650226655.


trigger AccountTrg on Account (before update) {


    List<Account> accountList=Trigger.New;

    for(Account acc:accountList){

        if(acc.Industry=='Banking'){

            acc.phone='8650226655';

        }

    }

       

}


Ex 2:- write a trigger to restrict the updation of an account record where rating was Hot.

Ans:-

//write a trigger to restrict the updation of an account record where rating was Hot.

trigger AccountTrg on Account (before update) {


List<Account> accList=Trigger.Old;

    for(Account acc:accList){

        if(acc.rating=='Hot'){

            //I cant use addError method of records fetched through Trigger.Old or Trigger.OldMap

           

            

            //I do have existing or old version of the record in acc , but to show the error we need to fetch the 

            //new version of record which can be done using Trigger.New or Trigger.NewMap . Trigger.NewMAp is appropriate

            // to record on the basis of record Id of acc I can its new version of record.

            

            //Here Trigger.newMap will provide the map of the new version of records from that map , we fetched

            //the new version of record on the basis of record Id..

            Account newAcc=Trigger.newMap.get(acc.Id);

            newAcc.addError('Account with existing rating as hot cant be updated...');

        }

    }

        

       

}


Ex 3:-  Whenever an account phone is modify then update all the contacts of the account.

1. contacts other phone as old phone of account

2. contacts mobile phone as newphone of account.

 

/*Whenever an account phone is modify then update all the contacts of the account.

1. contacts other phone as old phone of account

2. contacts mobile phone as newphone of account*/

trigger AccountTrg on Account (before update) {

    

    List<Contact> contactList=new List<Contact>(); //created an empty list of contact type..

    

    //Here we are fetching the list of new version of accounts which are getting updated with their related contacts

    List<Account> accList=[select Phone,(Select OtherPhone,mobilephone from contacts) from Account where Id 

                           in :Trigger.New];

    for(Account acc:accList){

        //Get the old version of account acc

        Account oldAcc=Trigger.oldMap.get(acc.Id);

        if(acc.Phone!=oldAcc.Phone){

            List<Contact> cons=acc.contacts;

            for(Contact c:cons){

                c.otherphone=oldAcc.phone;

                c.mobilePhone=acc.phone;

                contactList.add(c);

            }

        }

            

    }

update contactList;

}


Q :- Write a trigger to restrict the creation of account 

with duplicate name..


trigger AccountTrg on Account (before insert) {

    

    List<String> accountNames=new List<String>(); //Here i have created a list of string type

    

    //In this loop , we have fetched the name of those which are getting inserted , and those names we are 

    //storing in the list

    for(Account acc:Trigger.New){

        accountNames.add(acc.Name);  

    }

    

    //Here write a query to fetch all those accounts whose name is equal to the account name we are trying to insert.

    List<Account> accList=[select ID,NAme from account where Name in :accountNames];

    for(Account acc:Trigger.New){ //Iterate over the new accounts which are getting inserted

        for(Account acc1:accList){ //Iterate over the duplicate accounts 

            if(acc.name==acc1.Name){ //Will compare the name

                acc.addError('Duplicate Name . account with name '+acc.Name +' already exist');

            }

        }

    }

    

}



- Can i use context variables Trigger.Old and Trigger.OldMap in before and after insert trigger 

:-  No


- Can we use context variable Trigger.newMap in before insert trigger.

Ans :- WE cant Trigger.NewMap bcz Trigger.NewMap is a map which consist of record Id as the key and record as the value and we dont have the record Id before insert..


- Can we use context variable Trigger.newMap in after insert trigger.

Ans :- Yes


- Can we use Trigger.NEw , Trigger.NewMap , Trigger.Old and Trigger.Old in Before and after update trigger.

Ans :- Yes..


Testing :-


Testing is a process in software development where we need to check

whether our code is working as expected , we do have different types of testing such as

Unit TEsting , Integration Testing , System TEsting , Acceptance testing etc,,


Here we need to focus on Unit Testing. Unit testing is the testing which is performed by individual developers to verify whether the code developed is working as expected or not..


Testing in Apex  :- Apex provides a testing framework that allows you to write unit tests , run  the test and check that result is as per our expectations .



Why Unit testing is required:-

1. To validate that code is working as expected.

2. Reduce the Bug cost

3. 75% code coverage is required if we want to deploy our code(Apex class)  into production


What to test :-

1. Apex class (75% min code coverage is required)

2. Apex Trigger (1% min code coverage is required)


How to write a test class :- U need to annotate your class with @isTest annotation and test methods need to be annotated with @isTest also.


Syntax :-


@isTest

class MyTestClass {

@isTest

static void myTest(){

}


static testmethod void myTest(){

}

}



There are two ways for creating test method :-

1. Using @isTest annotation

2. Using testmethod keyword(deprecated and salesforce doesnt recommended to use it)



Note :- test methods must be static and must not be taking any arguments


Few Imp. Points :-

1. Data which is prepared in test method for the testing purpose will not be committed or saved into the salesforce org..

2. In the test method we cant access the org data.If you want to access the org data u need to write :-  @isTest(seeAllData=true) .It is not recommended to use org data for testing

3. The test data prepared in one test method wont be accessible to another test method even of the same test class.

4. If you want to share the test data among multiple test method of your then create a method and annotate it with @tESTSetUp annotation. The testing data prepare in test set up method will be accessible to all the test methods of your class  .

5. IF any of the test method has done any kind of changes in the data prepared through test set up method , those changes wont be visible to another test method...

6. It is recommended to perform testing  for the bulk records , minimum testing should be on 200 records.




Writing test class for the trigger"


Q :- Create a trigger to check whether the phone number is specified or not while updating the contact..


trigger PhChkTrigger on Contact (before update) {

    

    for(Contact cObj:Trigger.New){

        if(cObj.phone==null){

            cObj.addError('Phone Number must be specified');

        }

    }


}


@isTest

public class PhChkTrigger_Test {


    @isTest

    static void myTestMethod(){

        //how to test my trigger..

        

        Contact c=new COntact(firstName='Jatin',lastName='Aggarwal');

        insert c; //create a contact

        

        c=[select firstName,lastName from Contact];

        c.lastName='Agarwal';

        c.phone='7485968596';

        Database.SaveResult res=Database.update(c,false);

        System.assert(res.isSuccess()==true);

    }

    @isTest

    static void myTestMethod2(){

        Contact c=new COntact(firstName='Jatin',lastName='Aggarwal');

        insert c; //create a contact

        

        c=[select firstName,lastName from Contact];

        c.lastName='Agarwal';

        Database.SaveResult res=Database.update(c,false);

        System.assert(res.isSuccess()==false,res);

    }

}


Note :- As of now we have prepared the testing data either in the test method or in the testsetup method , but if we want we can have the test method in a csv file and can upload that csv file in static resource from the Quick Find . and that static resource can be used to access the test data using Test.loadData() method.. (home-work)


https://www.jitendrazaa.com/blog/salesforce/using-test-loaddata-to-import-records-with-relationship/


Any doubts?  - Atleast 2 questions will be there in exam from testing - one will be on Test.loadData..



@TEstVisible:-


public class TVREmoteControlClass {

integer volume ; //instance variable

    

    static final integer Max_volume=50; //static and final will make this variable as constant for all the object of this class.

 

    //parameterized constructor

    public TVRemoteControlClass(integer volume){

        this.volume=volume;

    }

    //This is private method so it is not visible outside the class not even to the test class.

    @TestVisible //this annotation will make the method visible to the test class.

    private integer increaseVolume(integer v){

        volume=volume+v;

        if(volume>Max_volume){

          volume=Max_volume;

        }

        return volume;

    }

    public integer decreaseVolume(integer v){

        volume=volume-v;

        if(volume<0){

          volume=0;

        }

        return volume;

    }

}


@isTest

public class TVRemoteControlTestClass {

    

    

    public testmethod static void increaseVolumeTest(){

        TVRemoteControlClass obj=new TVRemoteControlClass(20);

         integer newVol=obj.increaseVolume(5);

         System.assertEquals(25, newVol, 'Your test case has been failed....');

}

    @isTest

    public static void increaseVolumeTest2(){

        TVRemoteControlClass obj=new TVRemoteControlClass(20);

         integer newVol=obj.increaseVolume(35);

         

         System.assertEquals(50, newVol);

}

    @isTest

    public static void decreaseVolumeTest(){

        TVRemoteControlClass obj=new TVRemoteControlClass(20);

         integer newVol=obj.decreaseVolume(5);

         System.assertEquals(15, newVol, 'Your test case has been failed....');

}

    @isTest

    public static void decreaseVolumeTest2(){

        TVRemoteControlClass obj=new TVRemoteControlClass(20);

         integer newVol=obj.decreaseVolume(21);

         System.assertEquals(0, newVol, 'Your test case has been failed....');

}


}


Asynchronous Apex :

-----------------

Asynchronous process  is a process or function that executes a task in the background in a seperate thread without the user having to wait for the task to finish and user can continue with his other tasks.


We can typically use asynchronous apex for callouts to external system , operations that require higher governor limits and code that needs to be run at a certain time..


There are four ways of implementing asynchronous processs in apex:-

1. future method

2. batch apex

3. queueable apex

4. Schedulable apex


future method:-

1. A future method runs in the background.


2. You can also use of future method to isolate DML operations on different sobject types to prevent the mixed DML error.

What is mixed DML error:- When we perform the DML operations on set up as well as non set up objects in a single transaction then we will get the mixed DML Error.

What is set up and non-set up objects?- Set up objects are those objects which affects the security of the salesforce org e.g. User with a role , Profile or permission set . All other objects which doesnt effect the security are the non set up objects e.g. Account , contact etc. and all the custom objects.


3. Each future method will be executed in a seperate thread whenever the required resources will become available.


4. Future method can also be used to do the API Callout from the trigger. If there is any need to call the external Api from the trigger then that can be done with the future method..


Syntax of future method:-


@future

public static void myFutureMethod(){

}


1. method must be annotated with @future

2. method must be static and void

3. method can only take primitive or list of primitive as the argument




Limitations of future methods:-

1. cant be monitored

2. Cant passed sobject or list of sobject as the argument in the futuremethod



e.g.:-


public class FutureDemo {


    @future

    public static void myTask(){

        

        Profile p=[select Id from Profile where Name='standard User'];

        UserRole r=[select Id from UserRole where Name='CEO'];

        User u = new user();

u.LastName = 'Test Code 1';

u.Email = 'd.g@ABC.com';

u.Alias = 'Tcode1';

u.Username = 'test123444412@ABC.com';

u.CommunityNickname = 'test123';

u.LocaleSidKey = 'en_US';

u.TimeZoneSidKey = 'GMT';

u.ProfileID = p.Id;

u.LanguageLocaleKey = 'en_US';

u.EmailEncodingKey = 'UTF-8';

       u.userRoleId=r.Id;

Database.SaveResult res=Database.insert(u,false);

        if(res.isSuccess()){

            System.debug('OK');

        }        

        else {

            System.debug(res.getErrors());

        }

        

    }

    

}


In anonymous window:-

Account acc=new Account(name='Test acc 12 Oct');

insert acc;  //Non set up object


FutureDemo.myTask(); //Here set up object..


/*If we will perform DML on set up and non-set up 

object then we will get the mixed DML Error.. To solve

this one of the task cant be done in seperate thread

using future*/


Batch Apex 

Queueable 

Schedulable - 45 mins...


aura components :- 










What is Asynchronous Process ?-

Asynchronous process is a process that executes a task in the background 

in a seperate thread without the user having to wait for the task to get completed.

We can typically use asynchronous process for callouts to external applications , operations that require higher governor limit and i want to schedule the task for some specific point of time.

Four ways of implementing asynchronous process?

1. future method

2. batch apex

3. Queueable apex

4. Schedulable apex


Future method:-


Uses of future :-

1. To prevent Mixed DML Error

2. To make callout for external applications through the trigger.

3. If we want to perform some task in future whenever the resources becomes available or if that task is taking a large amount to get completed that also can be done in seperate thread using the future method.


Questions related to future method:-

1. Can we pass sobject as the argument of the future method?

Ans :- No , future method can only take primitive or list of primitive as the arguments.


2. Can future be monitored?

Ans :- No


3. Can one method call another future method?

Ans - No , future cant be called from another future . future cant be called from batch apex or batch apex cant be called from future.


Batch Apex :-

------------

Batch apex is a piece of apex code that runs asynchronously whenever the resources will become available . 


Use of Batch Apex :-

Whenever we want to process a large number of records then we can use batch apex . Batch apex can process upto 50 million records..


Syntax :-


public class AccountBatch implements Database.Batchable<SObject>{

    public Database.QueryLocator start(Database.BatchableContext bContext){

        return null;

    }

    public void execute(Database.BatchableContext bContext,List<SObject> slist){

        

    }

    public void finish(Database.BatchableContext bContext){

        

    }

}


To create a batch apex , we need to implement Database.Batchable interface and we know if will implement an interface we have give body to all its three methods which are explained below :-


1. start method:- start method is the starting point of the batch apex which will fetch the data using Database.QueryLocator to be processed by batch apex . We are using Database.QueryLocator because of its higher governor limits..


2. execute method :- execute method is the heart of the batch apex which takes the list of records  given by the start method and will process them . execute method will be called multiple times.


3. finish :- is the last method of the batch apex , where we can write the exit functionality like here we can send the email to the user that batch processing has been done..


How to call the batch apex :-

1. Create the object of your class:-

AccountBatch obj=new AccountBatch();


2. 


Database.executeBatch(obj);  //By default it will process 200 records at a time in the execute method. For example if ur QueryLocator is fetching 1000 records then the execute method will be fired 5 times.. 


If we want we can specify the records we want to process at a time.


Database.executeBatch(obj,10);


e.g.:-

/*By default , Batch apex will not maintain the state of variables between different transaction so 

if we want to maintain that you need to implement Database.Stateful and now you can maintain the 

value of instance variable b/w different transaction..*/

public class AccountBatch implements Database.Batchable<SObject>,Database.Stateful{

    

     integer count=0;

    

    public Database.QueryLocator start(Database.BatchableContext bContext){

        Id jobId=bContext.getJobId();

        AsyncApexJob apexJob=[select Id,JobType,status,methodName from AsyncApexJob where Id=:jobId];

        System.debug(apexJob.jobType+' '+apexJob.status+' '+apexJob.methodName);

        

        return Database.getQueryLocator([select Id,Name,Industry from account]);

    }

    public void execute(Database.BatchableContext bContext,List<Account> slist){

        count++;

        for(Account acc:sList){

                acc.Industry='Banking';

        }

        update sList;

    }

    public void finish(Database.BatchableContext bContext){

        System.debug('I m finish '+count);

    }

}


In anonymous window:-

AccountBatch obj=new AccountBatch();

Database.executeBatch(obj,10);


Ex:- Develop a  simple batch apex which will:-

1. Update the contact fax with account fax if contact fax is null

2. Update the contact mobile phone with account phone if contact phone is null

3. update email with abc.d@ABC.in

4. Update description with account name+ Account Industry+ Rating + contact email

5. Send the notification mail to the user ABC when batch executed and in email u need to send the no. of records processed and total no. failures.




public class ContactBatch implements Database.Batchable<SObject>,Database.Stateful{

    

    private integer totalRecords=0 , successSize=0,failSize=0;

    

    public Database.QueryLocator start(Database.BatchableContext bcon){

        return Database.getQueryLocator('select Id,Name,Fax,email,mobilephone,description,account.name,account.rating,account.phone,account.fax,account.Industry from Contact');

    }

    public void execute(Database.BatchableContext bcon,List<Contact> cList){

        totalRecords=totalRecords+cList.size();

        for(Contact cObj:cList){

            if(cObj.fax==null||cObj.fax==''){

                cObj.fax=cObj.Account.fax;

            }

            if(cObj.mobilePhone==null||cObj.mobilePhone==''){

                cObj.mobilePhone=cObj.Account.phone;

            }

            cObj.email='abc.d@ABC.in';

            cObj.description=cObj.Account.Name+' '+cObj.Account.Rating+' '+cObj.Account.Industry+' '+cObj.Email;

        }        

        List<Database.SaveResult> results=Database.update(cList,false);

        for(Database.SaveResult res:results){

            if(res.isSuccess()){

                successSize++;

            }

            else {

                failSize++;

            }

        }

    }

    public void finish(Database.BatchableContext bCon){

        Messaging.SingleEmailMessage email=new Messaging.SingleEmailMessage();

        email.setSubject('Status of the Contact Batch');

        email.setSenderDisplayName('Wipro Team');

        email.setHtmlBody('Dear User , Batch Processed'+

                         '<br/> Total Records '+totalRecords+

                         '<br/> Success Records :'+successSize+

                         '<br/> Failed Records : '+failSize);

        

        List<String> emailTo=new List<String>();

        emailTo.add('abc.d@ABC.in');

        email.setToAddresses(emailTo);

        

        List<Messaging.SingleEmailMessage> emailList=new List<Messaging.SingleEmailMessage>();

        emailList.add(email);

        

Messaging.sendEmail(emailList);

    }


}


Queueble Apex :-

Queueable jobs are similar to future methods in which they are queued for execution and will be executed in future whenever the resources will become available. But Queuable provides some additional benefits over the Queuable apex :-


1. Queueable is an interface whereas future is a method.

2. Future cant be monitored , Queueable can be monitored

3. Queuable can work with sobject or list of sobject whereas future cant

4. future cant call another future or batch whereas In queuable , chaining of jobs can be done..


e.g. :-


public class MyQueueuable implements Queueable{

    

    public void execute(QueueableContext context){

        Account a=new Account(Name='Queueable Account',phone='8596859685');

        insert a;

    }


}


In anonymous window:-


MyQueueuable obj=new MyQueueuable();

Id jobId=System.enqueueJob(obj);

System.debug('Job with Job Id '+jobId+' executed succesfully');


e.g. 2:-


public class Q_ClassDemo implements Queueable{

    

    public Account acc;

    

    public Q_ClassDemo(Account acc){

        this.acc=acc;

    }

    

    public void execute(QueueableContext qContext){

        this.acc.Name='Update Account';

        this.acc.Industry='Education';

        update acc;

    }


}


Anonymous Window:-

Q_ClassDemo obj=new Q_ClassDemo([select Id,Name,Industry

                                 from Account

                                where Name='Queueable Account' 

                                 limit 1]);

Id jobId=System.enqueueJob(obj);

System.debug('Job with Job Id '+jobId+' executed succesfully');



Schedulable Apex :-

1. schedulable apex is used to schedule the apex code to be done at some specified point of time



public class MySc implements Schedulable{

    

    public void execute(System.SchedulableContext scon){

        Account acc=new Account(name='Schedulable Account',Industry='Technology');

        insert acc;

    }


}


MySc obj=new MySc();

// Seconds Minutes Hours Day_of_month Month Day_of_week optional_year

String sch = '0 45 10 1/1 * ? *';

String jobID = 

   System.schedule('My First scheduled Job',sch,obj);


There are two ways to schedule the job - one using cron string and second from UI go to Quick Find - Apex Classes - Schedule Apex


Q 1:-  Where are two locations a developer can look to find information about the status of asynchronous or future calls? Choose 2 answers 


A. Time-based workflow Monitor

B. Apex Flex queue

C. Paused Flow Interviews component

D. Apex Jobs 


Ans:- D and B


Q 2:- What are two ways a developer can get the status of an enqueued job for a class that implements the queueable interface? 

A:- View the Apex Flex Queue

B:- View the Apex Status Page

C:- View the Apex Jobs Page

D:- Query the AsyncApexJob object


Q 3:- If Apex code executes inside the execute () method of an apex class when implementing the Batchable interface, which two statements are true regarding governor limits? 


Ans:- 

A:-  The Apex governor limits might be higher due to the asynchronous nature of the transaction 

B:-  The Apex governor limits are reset for each iteration of the execute () method. 


execute() method of batch apex :-  


Total records - 100 records 

chunk size :- 20


first 20 records will be processed 

now in next iteration , governor limits will be refreshed u will get new set of governor limits


Q 4:- 

Universal Containers recently transitioned from Classic to Lightning Experience. One of its business processes requires certain values from the Opportunity object to be sent via an HTTP REST callout to its external order management system based on a user-initiated action on the Opportunity detail page. Example values are as follows: Name         Amount         Account 

Which two methods should the developer implement to fulfill the business requirement? Choose 2 answers


A. Create a Process Builder on the Opportunity object that executes an Apex immediate action to perform the HTTP REST callout whenever the Opportunity is updated.


B. Create a Visualforce page that performs the HTTP REST callout, and use a Visualforce quick actionto expose the component on the Opportunity detail page.


C. Create an after update trigger on the Opportunity object that calls a helper method using  @Future(Callout=true) to perform the HTTP REST callout.


D. Create a Lightning component that performs the HTTP REST callout, and use a Lightning Action to expose the component on the Opportunity detail page


Ans :- C and D


Home-work :- Please do the trailhead of asynchronous apex


What is Lightning Component Framework :- 


  The lightning component framework is a UI framework for developing single page applications for mobile and desktop devices. You can build lightning component User Interfaces using two programming models :=


1. Aura Component model

2. Lightning Web component model (LWC)


What is Single page application:- A single page application is an application that workds inside a browser and doesnt require page reloading . We are using this type of application every day . e.g. Gmail , Google Maps , Facebook or Github.

SPA is just a one web page that you visit which then loads all other components using javascript.


Introduction to Aura Component model:-

1. Lightning aura is a programmin model or we can say it is a UI framework which is used to develop single page applications on the salesforce platform.

2. In aura component model , we will develop reusable units in the form of components

3. Multiple components will weave together to create an application.

4. It works on client side

5. Follows the event - driven architecture.


Benefits or why should I use  the aura component model:-

1. Device aware and cross browser compatibility :- It is responsive.

2. Out of the box components :- Aura Framework comes with an out-of-box set of components to kick start building apps.

3. Faster than the visualforce :- 

4. Rich component ecosystem- here we can create business ready components and make them available in the salesforce mobile app , lightning experience and so on.

5. Lightning apps can be used in visualforce pages or external applications using lightning out component.


Lets create the first aura component:- Go to the developer console - New - Lightning component


<aura:component implements="flexipage:availableForAllPageTypes">

<h1>I am a lightning component</h1>

</aura:component>


Note:- To see the preview of the aura component you need to set up the MyDomain , U will go to Quick Find - My Domain - Specify the Domain - Register My Domain - It will take few minutes to register the domain - once registered - Login In and test and after that deploy it to your users...


Lightning component bundle:- Once you will create a lightning aura component , that lightning aura component will consist of multiple files and thats why it is known as lightning component bundle. The different files consist in a lightning component model are as follows :-


1. component :- This is the file where we will write the UI Code that we want to display to the user.

2. Controller :- It is a javascript client side controller file . Here we will write all the operations to be performed whenever user interacts with the UI Component.

3. helper :- helper is also a javascript file which consist of reusable piece of code which can be used repeatedly in the controller.

4.  css styles = contains styling for the lightning component

5. documentation:- Specify the documentation for the lightning aura component .

6. Renderer - tells or overrides how your lightning component should be rendered(displayed)

7. SVG File - will declare all the icons to be used in my lightning aura component..



e.g. 


<aura:component implements="flexipage:availableForAllPageTypes">

    <div class="slds-p-around_large">

<h1 class="head">I am a lightning component</h1>

    </div>    

</aura:component>


<!-- slds is salesforce lightning design system. It consist of several css classes which can help 

to style our lightning components-->

<aura:application extends="force:slds">

    <c:FirstComp/>

</aura:application>



Attributes in lightning aura components :-

1. Attributes in lightning components are same as variables in the apex class.

2. For taking input or displaying the output we will use attributes

3. Attributes follow two way data binding .. 


<aura:component >

    

    <aura:attribute name="wholeNum" type="integer"/>

    <aura:attribute name="percentage" type="integer"/>

    

    <div class="slds-p-around_small">

    <lightning:input type="number" name="input1" 

                     label="Enter the Whole Number" value="{!v.wholeNum}"/>

    <lightning:input type="number" name="input2" 

                     label="Enter the percentage" value="{!v.percentage}" />

        

    

    {!v.percentage} of {!v.wholeNum} is  {!div(mult(v.percentage,v.wholeNum),100)}

        

     

    </div>

</aura:component>


Here {!} - It is an expression , anything written within this will be evaluated and then will get displayed.


{!v} :- v is a value provider , it is used to access the value from the attribute or set the value in the attribute..


e.g. showing two-way data binding:-


<aura:component >

    <aura:attribute name="EmpName" type="string" default="ABC"/>

    

    <div class="slds-p-around_small">

        <lightning:input type="text" name="input1" label="Enter your Name" value="{!v.EmpName}"/>

        

        <br/>

        

        Hello , {!v.EmpName}

    </div>

    

</aura:component>


e.g. CalculatorEx


<aura:component >

    <aura:attribute name="input1" type="integer"/>

    <aura:attribute name="input2" type="integer"/>

    <aura:attribute name="output" type="integer"/>

    

    <div class="slds-p-around_small">

        <lightning:input type="number" value="{!v.input1}" label="Please enter the first number"

                         required="true"/>

        <lightning:input type="number" value="{!v.input2}" label="Please enter the second number"

                         required="true"/>

        

        The Output is : {!v.output}

        

        <lightning:button variant="brand" label="Add" title="Add" onclick="{! c.doAdd }" />

        <lightning:button variant="brand" label="Subtract" title="Subtract" onclick="{! c.doSubtract }" />

        <lightning:button variant="brand" label="Multiply" title="Multiply" onclick="{! c.doMultiply }" />

        <lightning:button variant="brand" label="Divide" title="Divide" onclick="{! c.doDivide }" />

    </div>

    

</aura:component>


controller:-


({

doAdd : function(component, event, helper) {

var num1=component.get('v.input1');

        var num2=component.get('v.input2');

        

        var res=parseInt(num1)+parseInt(num2);

        //alert('Add : '+res);

        component.set('v.output',res);

},

    doSubtract : function(component, event, helper) {

var num1=component.get('v.input1');

        var num2=component.get('v.input2');

        

        var res=parseInt(num1)-parseInt(num2);

        //alert('Add : '+res);

        component.set('v.output',res);

},

    doMultiply : function(component, event, helper) {

var num1=component.get('v.input1');

        var num2=component.get('v.input2');

        

        var res=parseInt(num1)*parseInt(num2);

        //alert('Add : '+res);

        component.set('v.output',res);

},

    doDivide : function(component, event, helper) {

var num1=component.get('v.input1');

        var num2=component.get('v.input2');

        

        var res=parseInt(num1)/parseInt(num2);

        //alert('Add : '+res);

        component.set('v.output',res);

}

})


Now there is a requirement to add this calculator lightning component on the Home page of the application..


Go to the Home Page - Edit Page - 


But to show this lightning on the Home page first implements implements="flexiPage:availableForAllPageTypes" interface as mentioned below:-


<aura:component implements="flexiPage:availableForAllPageTypes">



e.g.:- Lets write a example to interact with the salesforce org data through the lightning component :-


step 1:- Create a server side controller which is my apex class which will fetch the data from the salesforce..


public class MyOpportunityListController {


    @AuraEnabled

    public static List<Opportunity> fetchOpportunity(String str){

        if(str==null||str==''){

        return [select Id,Name, closeDate ,Account_Name__c,Amount from Opportunity limit 10];

        }

        else {

            String search='%'+str+'%';

            return [select Id,Name, closeDate ,Account_Name__c,Amount from Opportunity where Name like :search limit 10];

        }

    }

}

step 2:- now lets create a lightning aura component


<aura:component controller="MyOpportunityListController" implements="flexipage:availableForAllPageTypes">

    

    <aura:attribute name="lstOpportunity" type="Opportunity[]"/>

    <aura:attribute name="columns" type="List"/>

    <aura:attribute name="searchTxt" type="string"/>

    

    <!-- Method to be called when component get initialized-->

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

    

    <div class="slds-p-around_small">

    

    <lightning:card iconName="standard:opportunity" title="Opportunity List">

    

        <aura:set attribute="actions">

            <lightning:input aura:id="searchField" label="Opportunity Name" value="{!v.searchTxt}"

                     placeholder="Search Opportunities" onchange="{!c.searchOpportunities}"/>

        

        </aura:set>

        

         <p class="slds-p-horizontal_small">

    <lightning:datatable

                keyField="id"

                data="{! v.lstOpportunity }"

                columns="{! v.columns }"

                             hideCheckboxColumn="true"/></p>

    </lightning:card>

        

      </div>  

</aura:component>


step 3:- create client side controlleR:-


({

doInit : function(component, event, helper) {

         component.set('v.columns', [

            {label: 'Opportunity name', fieldName: 'Name', type: 'text'},

             {label: 'Account name', fieldName: 'Account_Name__c', type: 'text'},

            {label: 'Close date', fieldName: 'CloseDate', type: 'date'},

            {label: 'Amount', fieldName: 'Amount', type: 'currency'}

            

        ]);

        

helper.fetchOppHelper(null,component);

        

},

    searchOpportunities : function(component, event, helper) {

        var searchStr=component.get('v.searchTxt');

        helper.fetchOppHelper(searchStr,component);

       

    }

})


step 4:- helper

({

fetchOppHelper : function(searchValue,component) {

//step 1:specify the action ie. method of the server side controller to be called.

        var action=component.get('c.fetchOpportunity');

        

        

        //step 2 :Pass the parameters to the server side controller 

        //here u can also specify the parameters to be passed to the server side controller..

        action.setParams({

            "str":searchValue

        });

        

        //step 3:- specify what to be done when response will come from the server

        action.setCallback(this,function(response){

            var state=response.getState();

            if(state==='SUCCESS'){

               

                component.set('v.lstOpportunity',response.getReturnValue());

            }

            else {

                alert('Some error occured');

            }

        });

        

        //step 4:- Send the action to be performed..

        $A.enqueueAction(action);

}

})


Communication between the components :-


1. Aura components follow the event driven architecture.

2. There are 2 types of events which are used for communication between components:-

a) Component Event

b) Application Events


Component Event :- 

1. Component event is fired from the child component and handled in the parent  

component.



Ex:- 


Step 1:- Create a event File- New - Lightning Event


<aura:event type="Component" description="Event template">

    <aura:attribute name="message" type="string"/>

</aura:event>


Step 2 :- Create the child Component where we will register the event and will fire it


<aura:component >

    

    <aura:registerEvent name="myCompEvent" type="c:CompEvent"/>

<h1>Simple example of component event</h1>

    <p>

        <lightning:button label="Click Here" onclick="{!c.fireComponentEvent}"/>

    </p>

    

</aura:component>


controller of child component


({

fireComponentEvent : function(component, event, helper) {

var cmpEvent=component.getEvent("myCompEvent");

        cmpEvent.setParams({

            "message":"Hello"

        });

        cmpEvent.fire();

}

})


Step 3:- Create the parent component which will handle the event

<aura:component >

    <aura:attribute name="messageFromChildThroughEvent" type="string"/>

    

    <aura:handler name="myCompEvent" event="c:CompEvent" action="{! 

c.handleComponentEvent}"/>

    

    <c:ChildComp1/>

    <p>{!v.messageFromChildThroughEvent}</p>

    

</aura:component>


controller:-

({

handleComponentEvent : function(component, event, helper) {

var msg=event.getParam("message");

        component.set('v.messageFromChildThroughEvent',msg);

}

})


Step 4:- Create a lightning application:-


<aura:application extends="force:slds">

    <c:ParentComp1/>

</aura:application>


Application Events :-

1. Application events follow a publish-subscribe model. an application event is fired  

from a component and any component which is having the handler can handle that event.


Application event propogation :- The framework supports capture and bubble phase for the  

propogation of the applications.


Bubble phase :- The source component which is the innermost component fires the event .  

Now when the event is generated , it travels up its hierarchy until its reaches the  

outermost component . This is called bubbling..


Capture phase :- Now when a event is fired from the outermost component to the inner  

most component .



Event - AppEvent

<aura:event type="APPLICATION" description="Event template" />



OwnerComponent.cmp:-


<aura:component >

    <aura:handler name="myAppEvent" event="c:AppEvent" action="{!c.handleAppEvent}"  

phase="capture"/>

    <c:ContainerComponent/>

</aura:component>


OwnerComponentController.js


({

handleAppEvent : function(component, event, helper) {

console.log('handle app event --- owner');

}

})


ContainerComponent.cmp:-


<aura:component >

<aura:handler name="myAppEvent" event="c:AppEvent" action="{!c.handleAppEvent}"  

phase="capture"/>

    <c:SourceComponent/>

</aura:component>


ContainerComponentController.js:-

({

handleAppEvent : function(component, event, helper) {

console.log('handle app event --- container');

}

})


SourceComponent.cmp:-


<aura:component >

    <aura:registerEvent name="myAppEvent" type="c:AppEvent"/>

    

    

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

    <aura:handler name="myAppEvent" event="c:AppEvent" action="{!c.handleAppEvent}"  

phase="capture"/>

    

    

</aura:component>


SourceComponentController.js


({

doInit : function(component, event, helper) {

var appEvent=component.getEvent("myAppEvent");

        appEvent.fire();

},

    handleAppEvent : function(component, event, helper) {

        console.log('handle app event --- source');

}

})


LightningApp:-


<aura:application extends="force:slds">

    <c:OwnerComponent/>

</aura:application>



What is Lightning Web component (LWC):-

--------------------------------------


LWC is a new programming model of the Lightning framework . They are custom html elements built using HTML and modern javascript..


Advantages of Lightning Web components 


1. Better performance

2. Easy to use

3. Compatible with aura components

4. Follows modern web standards .


What are web standards?- Web standards are the rules and guidelines which are established by W3C to provide consistency in the design code which makes up a web page.


Most common web standards are as follows:-

1. HTML

2. XHTML

3. Ecma script:- Ecmascript is a  javascript standard meant to provide interoperability of web pages across different web browsers. we do have different versions of Ecma script.

4. Events 

5. Rendering

6. Shadow DOM :- Shadow DOM allows us to create our own node trees which is known as shodow tree. These shadow tree encapsulate their contents and render only what they choose.


DOM :- DOM stands for Document Object Model . It is a tree representation of an HTML Document . It is used by web browsers to determine what to render on the page and by javascript programs we can modify the structure and styling of the page using DOM APIs.


- Now there can be one question which can come to our mind is - If LWC is so good then why salesforce has not introduced LWC directly , why salesforce introduced Aura first and now saying LWC is better. To answer this we need to go through the Web stack of 2014.

Web Stack of 2014:-













Here we can see the Web standard in 2014 were very week to make use to create UI Components . What is the problem with this approach :-

1. Hard to find workforce.

2. Components written in one framework, are different to migrate to another framework if needed

But in 2019 , Web stack has improved a lot . Web stack of 2019 were providing all the capabilities which can help to create UI Components such as :-

Web Components

Templates

Shadow DOM

Ecmascript 7

Events

Standard Elements

And so on.


So now  , salesforce has introduced so that it can make maximum use of standard web stack..

Lets see how to create a first lightning web component but before that you need to install all the required softwares , because LWC component cant be created on the Developer console.

1. Download and Install the Salesforce DX CLI :-

Salesforce CLI :- Salesforce CLI is a command line interface tool to interact with salesforce orgs  and manage metadata like

1. Create and manage metadata like apex class , lightning components etc.

2. Import and export data

3. Run apex test

4. Build automation..

Go to https://developer.salesforce.com/tools/sfdxcli and download for windows – Once it will get downloaded , u need to install it.

Now open the command prompt and ensure that salesforce cli has been installed properly or not by writing the command sfdx


2. Download and install the Visualstudio code from code.visualstudio.com/download

Download for window

3. Now open the visualstudio code

Now from the left hand side of the visualstudio code , U will go to the Extensions – Search for salesforce extension pack – click on that – and install it.

Now lets start working on visual studio code:- 

In salesforce we do have two types of development models:-

1. Org development model – In org development model , there will no code tracking ,no code versioning . It is used for practice purpose , in developer editions and in trailhead playgrounds..


2. Package development model

Lets see how to do org development model:

1) Press Ctrl+Shift+P on the VS Code – or Go to the View command palette – Create Project with Manifest – Standard Project Template- Specify the Project Name – specify the folder where u create the project 

2) Now authenticate ur org

Ctrl+Shift+P- Authorize a org – Project default – provide alias for ur org – click Enter – Will open the login page for your salesforce org – provide ur id and password – and if asked u need to click on Allow.

3. Now lets create a class in the VS Code.

Ctrl+Shift+P= Create Apex class- specify the name – select the default location.

4. Now lets deploy this class to the salesforce org.Right click on your class – Deploy source to Org -  Once deployed go to the salesforce org – In the Quick find box- search for Apex classes – There u can see ur class which has been deployed from VS Code and here you can make changes once changes will be done . Save the class and go to the VS code , now right click on the class in the VS Code and click retrieve source from Org to VS Code.


Lets see how to work with the scratch org?

But before learning about scratch Org we need to understand what is Salesforce DX?

1. Salesforce DX is an approach which streamlines the entire development life cycle.

2. It shifts the development model from org development to package development.

3. Salesforce DX provides the concept so that versioning control can be done into the code.

4. Salesforce DX will help you to create the scratch org.

Scratch Org :- Scratch orgs are the orgs consisting of salesforce code or metadata that can easily be created or destroyed , helping to speed up the standard development workflow.

Lets start source driven development using scratch orgs.

Step 1:- Create a new SFDx Project 

CTRL+shift+p – Create Project with Manifest =select standard –choose folder – Provide the name of the project

Step 2:- Authorize a Dev Hub

A dev hub provides the ability to create and manage scratch orgs.

From the command palette – select authorize a dev hub – will open the login page for the salesforce org – provide the Id and password and login for the same.

Step 3:- Now In your salesforce org , Go to the Quick Find – Search for Dev Hub and enable Dev Hub

Step 4 :- Create a default scratch org 

Go to the command palette – select create a default scratch org – choose project-scratch-def.org – Give an org alias – Select the no . of days for scratch org


Step 5 :- Now open the Default scratch org

Go to the command palette – and select open the default scratch org


Step 6:- Now create a apex class and from the command palette push to the scratch org


- Tomorrow we will see how to create a lightning web component in VS Code , how to run it and how to push it on the Scratch org..

- Will discuss the practice questions coming from the LWC topic

-



<template>

    <div class="slds-box">

        

        <h1>{message}</h1>

        

        <br/>

        

        <!--Here we want to update the value of message as per the value of this text field that we have 

        we are handling the onchange event of input fields..As soon as value of text field will be changed ,

        handleChange method of javascript will be called..-->

        <lightning-input type="text" label="Greetings" value={message} onchange={handleChange}>

        </lightning-input>


        <!--Now lets how to handle the events on button-->

        <p class="slds-m-vertical_medium">

            Hi ABC, {labelOfBtn}

        </p>


        <lightning-button variant="brand" label="Good Morning" name="Good Morning" title="Primary action" onclick={handleGoodMorning} class="slds-m-left_x-small"></lightning-button>


    </div>

</template>


js file:-


/*Every LWC component must have a javascript file. All the logic

is written inside this javascript file... */


import { LightningElement } from 'lwc';


export default class WiproLWCComp extends LightningElement {

   

    message='Good Morning All , Best of Luck for your certification exam';

    labelOfBtn='How r u??';



    handleChange(event){

        /*Here we will fetch the value of text field using event.target.. and assign it to the message variable. */

        this.message=event.target.value;

    }

    handleGoodMorning(){

        this.labelOfBtn=event.target.name;

        this.template.querySelector('p').style.color='red';

    }

}


css:-

h1{

    text-align:center;

    font-weight:bold;

    font-size:large;

    color:white;

}

.slds-box {

    background-color:blue;

}


Imp. Inks


1. https://www.youtube.com/watch?v=-OLnkdfd9rA

2. https://www.youtube.com/watch?v=O0I-h1fbVGQ

3. https://www.youtube.com/watch?v=iW7D2MMuRJs

4. https://www.youtube.com/watch?v=sFASunKo43Q

5. https://www.youtube.com/watch?v=_E8vl3OJOkA

Comments