Vous êtes sur la page 1sur 46

Apex & Visualforce -

Scenarios
Compare old values with new values
Scenario?
When ever a account is updated ensure that account number is not
changed

Solution?
What to use? : apex, Visualforce or apex triggers?

Triggers will only work..


If Tiggers how?
How to fetch the old records?
----------------trigger.oldmap----------------
How to fetch the new records?
----------------trigger.new---------------------
How to compare?
----------- == operator --------------
. Throw error message
-------- adderror() ------
Implementation
trigger AccountCheck on Account (before update) {

for(account newacc: trigger.new)


{
account oldacc = trigger.oldmap.get(newacc.id);
if(newacc.accountnumber!= oldacc.accountnumber)
{
System.debug('Old account number is changed');
newacc.accountnumber.adderror('Account Number is changed');
}
}
}
Validation
What is validation & why do we need
that?
Checking to make sure data is valid the checks are called validation and these
validation are two types (Client side and server side)
Without validation there are high chances of storing junk and wrong data in the system

Scenario?
Ex:- When user creates an account with annual revenue less than 2000 or Account
Source is blank then show error
BV

Solution?
Use either workflow, process builder or apex trigger
Solution with apex trigger
trigger AccountValidationTrigger on Account (before insert, before update) {
for(Account acc: Trigger.New)
{
if(acc.AccountSource == NULL)
{
acc.AccountSource.addError('Account Source is blank');
}
else if(acc.Annualrevenue <2000)
{
acc.AnnualRevenue.addError('Annual Revenue less than $2000 ');
}
}
}
Apex Trigger Bulkification
What is Trigger bulkification?
Simply it means writing code to handle many records at a time
instead of processing one record at a time

Scenario where bulkification is required?


Ex:- if Account record is updated with annual revenue more
than $1000 set account type as Prospect
When data is loaded using dataloader on one record or
multiple DML Statement will be fired which causes to hit
governor limit
Implementation
trigger updateAnnualRevenue on account(before update){
if(trigger.new[0].annualrevenue > 1000)
trigger.new[0].type = 'Prospect';
}

trigger updateAnnualRevenue on account(before update){


for(account acc:trigger.new){
if(acc.annualrevenue > 1000)
acc.type ='Prospect';
}
}
Common Issue with Trigger-
Recursive Trigger
Trigger is being called again and again.
For ex:- in update trigger if you use update dml statement will cause the error
Scenario:- update a record in update trigger scenario

trigger recursiveTrigger on Contact (after update) {


Id recordId ;
for(contact con : trigger.new){
recordId = con.id;
}
Contact conRec =[select id,name,email from contact where id !=: recordId limit 1];

conRec.email = 'testemail@kmail.com';
update conRec;
}
Solution
global Class recusrssionPreventController{
Global static boolean flag = true;
Public recusrssionPreventController(){
}
}

trigger recursiveTrigger on Contact (after update) {


Id recordId ;
if(recusrssionPreventController.flag == true){
recusrssionPreventController.flag = false;
for(contact con : trigger.new){
recordId = con.id;
}
Contact conRec =[select id,name,email from contact where id =: recordId limit 1];

conRec.email = 'testemail@kmail.com';
update conRec;
}
}
Revist some common Visualforce
Tags
To display Visualforce Page Like this
<apex:page standardController="account" recordSetVar="account">
<apex:form >
<apex:pageBlock >
Account details are below
</apex:pageBlock>
<apex:PageBlock >
<apex:PageBlockSection columns="3" >
<apex:PageBlockSectionItem >
<apex:dataTable value="{!account}" var="acc" >
<apex:column value="{!acc.name}" headerValue="Name"/>
<apex:column value="{!acc.accountnumber}" headerValue="Number"/>
</apex:dataTable>
</apex:PageBlockSectionItem>
<apex:PageBlockSectionItem > <apex:commandButton value="Second column"
action="New"/></apex:PageBlockSectionItem>
<apex:PageBlockSectionItem > <apex:commandLink value="ThirdLink"/></apex:PageBlockSectionItem>

</apex:PageBlockSection>
</apex:PageBlock>
</apex:form>
</apex:page>
Visualforce and apex combinations
Getting global and current page parameters

-- These parameters are required such as priniting the


username or getting current page parameters record id,
recordType etc
Implementation
<apex:page standardController="Account" extensions="DemoController">
<apex:form >
<apex:pageblock >
<apex:outputText value="{!LoggedInUSerId}"/>
<apex:outputText value="{!recordId}"/>
</apex:pageblock>
</apex:form>
</apex:page>
Public with sharing class DemoController {
Public Id LoggedInUSerId{get;set;}
Public string recordId {get;set;}
Public DemoController(ApexPages.StandardController controller) {
LoggedInUSerId = UserInfo.getUserId();
recordID = ApexPages.CurrentPage().getparameters().get('id');
}
}
Passing visualforce values to
controller and back to page
Implementation
---- Apex Class ------

Public with sharing class passparamController {


Public string myInput{get;set;}
Public string myoutput{get;set;}

Public void MyMethode(){


myoutput = myInput ;
}
}

=============-- -Visualforce -===========

<apex:page controller="passparamController">
<!-- Pass parameters from visualforce page to controller -->
<apex:form >
<apex:pageblock >
Input Here <apex:inputText value="{!myinput}"/>
<apex:commandButton value="Submit" reRender="outputID" action="{!MyMethode}"/>
</apex:pageblock>
<apex:pageblock >
<b>Output here = </b><apex:outputText value="{!myoutput}" id="outputID">
</apex:outputText>
</apex:pageblock>
</apex:form>
</apex:page>
Relationship Query
Scneario?
Whenever you want to show child records under parent
or parent records in child

Example please?
If you want to show contact records under account
Relationship Query Implementation
public with sharing class contrller {
Public id Current_Acc_Id;

public contrller(ApexPages.StandardController controller) {


Current_Acc_Id = controller.getRecord().id;
}

public List<Contact> getrelatedContacts(){


List <contact> conList = New List<Contact>();
for(Account acc:[select id,name,(select name,id,email from contacts) from account
where id=:Current_Acc_Id]){
for(contact con:acc.contacts)
conList.add(con);
}
return conList;
}
}
Implementation
<apex:page standardController="Account" extensions="contrller">
<apex:form >
<apex:pageblock >
<!-- Display Account related Contacts -->
<apex:pageBlockTable value="{!relatedContacts}"
var="val">
<apex:column value="{!val.name}"/>
<apex:column value="{!val.email}"/>
</apex:pageBlockTable>
</apex:pageblock>
</apex:form>
</apex:page>
Showing error messages
Scenario:-
Business scenario often requires validation on
form. Making sure user enters the right data
inorder to do that relevant error messages are
shown

Example:- Throw error message when account


name or number is null
Apex class
Public with sharing class ErrorDisplayDemoController {
Public string accountname{get;set;}
Public string accountnumber{get;set;}
Public ErrorDisplayDemoController(ApexPages.StandardController controller) {
}

Public void UpdateAccount(){


if(accountname == '' || accountname == null)
ApexPages.addmessage(new ApexPages.message(ApexPages.severity.WARNING,'Please
enter Account name'));

if(accountnumber == '' || accountnumber == null)


ApexPages.addmessage(new ApexPages.message(ApexPages.severity.error,'Please
enter Account number'));
}
}
Visualforce Pages
<apex:page standardController="Account" extensions="ErrorDisplayDemoController">
<apex:form >
<apex:pageblock >
<apex:pageMessages id="shwmsg"></apex:pageMessages>
<apex:panelGrid columns="2">
Account Name <apex:inputtext value="{!accountname}"/>
Account Number <apex:inputtext value="{!accountnumber}"/>
<apex:commandButton value="Update" action="{!UpdateAccount}"
style="width:70px" rerender="shwmsg"/>
</apex:panelGrid>
</apex:pageblock>
</apex:form>
</apex:page>
Wrapper Class
Why Wrapper class is needed?
List, set or map can ideally provide space to add only certain
datatypes. So, there is a need for special class that holds the
different datatype. This also hides the implementation details

Scenario?
If you want to display different objects or datatypes in a
single list ex: lets display 5 account records in table with
checkbox
Implementation
<apex:page standardController="Account"
extensions="WrapperDemoClass">
<apex:form >
<apex:pageblock >
<apex:pageblockTable value="{!wrapperObj}" var="Rec">
<apex:column value="{!Rec.accObj.name}"/>
<apex:column >
<apex:inputcheckbox value="{!Rec.checkBox}"/>
</apex:column>
</apex:pageblockTable>
</apex:pageblock>
</apex:form>
</apex:page>
Wrapper class
public with sharing class WrapperDemoClass {
Public List<WrapperClassEx> WrapperList{get;set;}
public WrapperDemoClass(ApexPages.StandardController controller) {

Public List<WrapperClassEx> getwrapperObj(){


List<Account> accList = [Select id,name from account limit 5];
WrapperList = New List<WrapperClassEx>();
for(Account acc: accList){
WrapperList.add(New WrapperClassEx(acc,false));
}
return WrapperList;
}

Public Class WrapperClassEx{


Public Account accObj{get;set;}
Public Boolean checkBox{get;set;}

Public WrapperClassEx(Account accRec, boolean SelectBox){


accObj = accRec;
checkBox = SelectBox;
}
}
}
Hide and show components
Scenario:-
Often there are requirements to hide some fields or component
based on certain condition

Example:-
If you want to display some block when command button is clicked

Solution:-
Rendered attribute
Public with sharing class hideblock{
Public Boolean ShowpageBlockFlag{get;set;}
Public Account accRec{get;set;}

Public hideblock(){
accRec = [select name,id,accountnumber from account limit 1];
ShowpageBlockFlag = false;
}

Public void ShowBlockMethod(){


ShowpageBlockFlag = true;
}
}

<apex:page controller="hideblock">
<!-- Render and Rerender Demo -->
<apex:form >
<apex:pageBlock >
<apex:commandButton value="Show Bottom Page Block" action="{!ShowBlockMethod}"/>
</apex:pageBlock>

<apex:pageBlock rendered="{!ShowpageBlockFlag}">
Account Name :<apex:outputField value="{!accRec.name}"/>
<br/>
Account Number :<apex:outputField value="{!accRec.accountnumber}"/>
</apex:pageBlock>
</apex:form>
</apex:page>
Refresh a component
Scenario:-
Based on a button click we might have to change the
value in a component
Public with sharing class RefreshComp {
Public string OutPutString{get;set;}

Public RefreshComp (){


OutPutString = 'Test value set in Constructor';
}

Public void ShowBlockMethod(){


OutPutString = 'value set in methode called by button click' ;
}
}

<apex:page controller="RefreshComp">
<!-- Render and Rerender Demo -->
<apex:form >
<apex:pageBlock >
<apex:commandButton value="Refresh Lower Page Block" action="{!ShowBlockMethod}" rerender="pgblckID"/>
</apex:pageBlock>

<apex:pageBlock id="pgblckID">
<b> Output Text : </b> <apex:outputText value="{!OutPutString}"/>
</apex:pageBlock>
</apex:form>
</apex:page>
Schema class
Scenario:-
Often there are situations where you might have get
objects and Fields data and most often it is used in
dynamic soql query construction

Example
If you want display all the objects data in a picklist
How do we access Schema Object
-------- Function to get all the objects data
--------------------
Schema.getGlobalDescribe().keyset();
---------------- What visualforce component displays
the picklist ---------
<Apex:selectlist> and
<apex:selectOption>
Display all the objects data in a
picklist
public class AllObjectsinOrg {
Public string ObjectSelected{get;set;}
Public Map<String, Schema.SObjectType> AllObjmap;
Public AllObjectsinOrg(){
AllObjmap = New Map<String, Schema.SObjectType>();
AllObjmap = Schema.getGlobalDescribe();
System.debug('******All object Names :'+ AllObjmap.keyset());
}
Public List<selectoption> getObjList(){
List<selectoption> objList = new List<selectoption>();
for(string s:AllObjmap.keyset()){
objList.add(new selectoption(s,s));
}
return objList;
}
}
Visualforce
<apex:page controller="AllObjectsinOrg">
<apex:form >
<apex:pageBlock id="pgblck">
<apex:outputlabel value="Object Name" for="ObjPickList"/>
<apex:selectList value="{!ObjectSelected}" multiselect="false"
id="ObjPickList" size="1">
<apex:selectOptions value="{!ObjList}"/>
</apex:selectList>
</apex:pageBlock>
</apex:form>
</apex:page>
Get all objects and fields using schema
public class AllObjectsandFields {
Public string ObjectSelected{get;set;}
Public string fldselected{get;set;}
Public Map<String, Schema.SObjectType> AllObjmap;
Public Map <String, Schema.SObjectField> fieldMap;
Public boolean rendflag{get;set;}
Public AllObjectsandFields (){
AllObjmap = New Map<String, Schema.SObjectType>();
AllObjmap = Schema.getGlobalDescribe();
System.debug('******All object Names :'+ AllObjmap.keyset());
}
Public List<selectoption> getObjList(){
List<selectoption> objList = new List<selectoption>();
for(string s:AllObjmap.keyset()){
objList.add(new selectoption(s,s));
}
return objList;
}
Public List<selectoption> getFieldList(){
List<selectoption> fldList = new List<selectoption>();
if(!fieldMap.isEmpty()){
for(string s:fieldMap.keyset()){
fldList.add(new selectoption(s,s));
}
if(fldList.size()== 0)
fldList.add(new selectoption('--None--','--None--'));
}
return fldList;
}
Public void fieldsofObject(){
fieldMap = New Map <String, Schema.SObjectField>();
fieldMap = AllObjmap.get(objectSelected).getDescribe().fields.getMap();
System.debug('###### all fields of object## :' + fieldMap.keyset());
Visualforce Page
<apex:page controller="AllObjectsandFields">
<apex:form >
<apex:pageBlock id="pgblck">
<apex:outputlabel value="Object Name" for="ObjPickList"/>
<apex:selectList value="{!ObjectSelected}" multiselect="false" id="ObjPickList" size="1">
<apex:selectOptions value="{!ObjList}"/>
<apex:actionSupport event="onchange" action="{!fieldsofObject}" rerender="pgblck" />
</apex:selectList><br/><br/>
<apex:outputlabel value="Field Name" for="fldPickList" rendered="{!rendflag}"/>
<apex:selectList value="{!fldselected}" multiselect="false" id="fldPickList" size="1" rendered="{!rendflag}">
<apex:selectOptions value="{!FieldList}"/>
</apex:selectList>
</apex:pageBlock>
</apex:form>
</apex:page>
Javascript and Visualforce pages
Visualforce tags that supports javascript are
<action:status>
<action:function>
<action:support>
<action:pollar>

Include Javascript in Visualforce page


<apex:includeScript value="{!$Resource.example_js}"/>
<link href="{!$Resource.fullCalendarPrintCSS}" rel="stylesheet"
media="print" />
Showing Status of the request
Public with sharing class actionstatusDemoController {
Public actionstatusDemoController(){
}

Public void demomethod(){


}
}

<apex:page controller="actionstatusDemoController">
<apex:form >
<apex:pageblock id="pgblck">
<apex:actionStatus id="actstatus" >
<apex:facet name="start" >
<img src="/img/loading32.gif" />
</apex:facet>
</apex:actionStatus>
<apex:commandButton value="Submit" status="actstatus" action="{!demomethod}" reRender="pgblck"/>
</apex:pageblock>
</apex:form>
</apex:page>
Call controller method from
javascript?
<apex:actionfunction> will call the controller method
from a javascript
Public class AFController {
Public string MyString_From_Methode{get;set;}
public AFController(ApexPages.StandardController controller) {
}
public string ActionFunMethode(){
MyString_From_Methode = 'Method called from js using Action function';
return null;
}
}

<apex:page standardcontroller="Account" extensions="AFController" tabStyle="Account">


<apex:form >
<apex:actionFunction name="actionFunName" action="{!ActionFunMethode}" reRender="outputtxtId"/>
<apex:pageBlock >
<apex:outputLabel for="inptCheckBox" value="Check this box to call Controller method from js using ActionFunction"
style="color:green;"></apex:outputLabel>
<apex:inputcheckbox onclick="javaScrpt()" id="inptCheckBox"/>
</apex:pageBlock>
<apex:outputText value="{!MyString_From_Methode}" id="outputtxtId"></apex:outputText>
</apex:form>
<script>
function javaScrpt(){
actionFunName();
}
</script>
</apex:page>
Adding javascript support to
components
<apex:actionsupport>
Action support component adds AJAX support to another
component, this allows the component to call a
controller method when a particular event occurs(for
example onlcik, onblur etc)
Implementation
Public with sharing class ASController {
Public String outValueSecond{get;set;}
Public String outvalue{get;set;}
Public boolean flag{get;set;}
Public ASController(){
outvalue = 'Before Value';
outValueSecond = 'before value set in constructor';
}
Public void DemoMethod(){
outValueSecond = 'After value set in controller method. This method is called using action support added to
inputtext compoennt';
}
}

<apex:page controller="ASController">
<apex:form >
<apex:pageBlock >
Click Inside this block <apex:inputtext >
<apex:actionSupport event="onclick" action="{!DemoMethod}" rerender="pgblck"/>
</apex:inputtext>
</apex:pageBlock>
<apex:pageblock id="pgblck">
<apex:outputText value="{!outValueSecond }"/>
</apex:pageblock>
</apex:form>
</apex:page>
Timer in Visualforce Page
Action poller acts as a timer in visuaflorce page. It is
used to send an AJAX request to the server depending
on the time interval (time intervalhas to be specified or
else it defaults to 60 seconds).
Implementation
Public with sharing class actionpollerDemoController {
Public Integer seconds{get;set;}
Public actionpollerDemoController(){
seconds = 0;
}

Public void CounterMethod(){


seconds = seconds + 5;
}
}

<apex:page controller="actionpollerDemoController">
<apex:form >
<apex:pageBlock id="pgplck">
<apex:actionPoller action="{!CounterMethod}" reRender="pgplck" interval="5"/>
{!seconds } seconds since the action poller was called !!
</apex:pageBlock>
</apex:form>
</apex:page>
Javascript remoting important
concept
What is a javascript remoting?
JavaScript remoting is a tool that front-end developers can
use to make an AJAX request from a Visualforce page
directly to an Apex controller.

Why this is needed?


JavaScript remoting allows you to run asynchronous actions
by decoupling the page from the controller and to perform
tasks on the page without having to reload the entire page
Visualforce
<apex:page controller="AccountRemoteActionController">
<script type="text/javascript">
function getAccountJS()
{ var accountNameJS = document.getElementById('accName').value;
AccountRemoteActionController.getAccount( accountNameJS,
function(result, event)
{
alert('event.status==>'+event.status); alert('event.type === '+event.type); alert('event.message ==>'+event.message);
if (event.status) {
document.getElementById("{!$Component.theBlock.thePageBlockSection.theFirstItem.accId}").innerHTML = result.Id;
document.getElementById("{!$Component.theBlock.thePageBlockSection.theSecondItem.accNam}").innerHTML = result.Name;
}
else if (event.type === 'exception') {
document.getElementById("errors-js").innerHTML = event.message;
} else
{
document.getElementById("errors-js").innerHTML = 'No Records Found..';
}
}, {escape:true});
}
</script>
Account Name :<input id="accName" type="text" />
<button onclick="getAccountJS()">Get Account</button>
<div id="errors-js"> </div>
<apex:pageBlock id="theBlock">
<apex:pageBlockSection id="thePageBlockSection" columns="2">
<apex:pageBlockSectionItem id="theFirstItem">
<apex:outputText id="accId"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem id="theSecondItem" >
<apex:outputText id="accNam" />
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
Apex class
global class AccountRemoteActionController
{
public String accountName { get; set; }
public static Account account { get; set; }
//Default Constructor..
public AccountRemoteActionController() {

@RemoteAction
global static Account getAccount(String accountName)
{
account = [select id, name, phone, type, numberofemployees from Account where name = :accountName ];
return account;
}
}

Vous aimerez peut-être aussi