Wednesday 13 June 2012

Data encapsulation in Visualforce page and controller

Generally visualforce page in salesforce usese page variables defined as public in controller which can be accessed directly which is not a good Object Oriented design. In this article i will show how to convert a normal visulaforce page which uses public variables to a much Object Oriented visualforce page which will use data encapsulation techinque to hide data by making it private.

A typical Visualforce page and controller looks like below :

<apex:page controller="TestController" >
<apex:form id="testForm">
<apex:pageBlock id="TestBlock">
  <apex:pageBlockSection title="Submitted Data"  rendered="{!isOutputRendered}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:outputText value="{!name}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:outputText value="{!product}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:outputText value="{!productManager}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:outputText value="{!description}"></apex:outputText>
   </apex:pageBlockSectionItem>
  <center>
<apex:commandButton value="Re-Enter Data" action="{!reEnterData}" reRender="testForm"/>
</center>
 </apex:pageBlockSection>
 <apex:pageBlockSection title="Enter Data" rendered="{!NOT(isOutputRendered)}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:inputText value="{!name}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:inputText value="{!product}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:inputText value="{!productManager}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:inputText value="{!description}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <center>
   <apex:commandButton value="Submit Data" action="{!submitData}" reRender="testForm"/>
   </center>
 </apex:pageBlockSection>

 </apex:pageBlock>
 </apex:form>
 </apex:page>

Controller for above page:

public class TestController
{
 public Boolean isOutputRendered{get;set;}
 public String description{get;set;}
 public String name{get;set;}
 public String product{get;set;}
 public String productManager{get;set;}

public TestController ()
{
  isOutputRendered=false;
}
public PageReference submitData()
{
 isOutputRendered=true;
 return null;
}
public PageReference reEnterData()
{
  isOutputRendered=false;
 return null;
}
}

Above page is a simple which takes user inputs and displays it back to user. Her if you observe all the page variables are defined as public which is not a good Object Oriented design.

Below is the transformed version of above page where page vairbales will be private and provide data encapsulation.

<apex:page controller="TestController" >
<apex:form id="testForm">
<apex:pageBlock id="TestBlock">
  <apex:pageBlockSection title="Submitted Data"  rendered="{!dataClass.isOutputRendered}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:outputText value="{!dataClass.name}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:outputText value="{!dataClass.product}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:outputText value="{!dataClass.productManager}"></apex:outputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:outputText value="{!dataClass.description}"></apex:outputText>
   </apex:pageBlockSectionItem>
  <center>
<apex:commandButton value="Re-Enter Data" action="{!reEnterData}" reRender="testForm"/>
</center>
 </apex:pageBlockSection>
 <apex:pageBlockSection title="Enter Data" rendered="{!NOT(dataClass.isOutputRendered)}">
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Name"></apex:outputLabel>
     <apex:inputText value="{!dataClass.Name}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product"></apex:outputLabel>
     <apex:inputText value="{!dataClass.product}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Product Manager"></apex:outputLabel>
     <apex:inputText value="{!dataClass.productManager}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
     <apex:outputLabel value="Description"></apex:outputLabel>
     <apex:inputText value="{!dataClass.description}"></apex:inputText>
   </apex:pageBlockSectionItem>
   <center>
<apex:commandButton value="Submit Data" action="{!submitData}" reRender="testForm"/>
</center>
 </apex:pageBlockSection>

 </apex:pageBlock>
 </apex:form>
 </apex:page>

TestController :

public class TestController {
 private TestDataClass dataClass=null;
 public TestDataClass getDataClass()
{
 return this.dataClass;
}
public TestController ()
{
 dataClass=new TestDataClass();
 dataClass.setIsOutputRendered(false);
}
public PageReference submitData()
{
 dataClass.setIsOutputRendered(true);
 return null;
}
public PageReference reEnterData()
{
 dataClass.setIsOutputRendered(false);
 return null;
}
}

If you would have observed in controller i have created a private variable 'dataClass' of  'TestDataClass'. TestDataClass is the class which will contain all the varibles which will be used in page.

TestDataClass:

public class TestDataClass
{
 private Boolean isOutputRendered;
 private String description;
 private String name;
 private String product;
 private String productManager;
 public Boolean getIsOutputRendered() {
  return isOutputRendered;
 }
 public void setIsOutputRendered(Boolean isOutputRendered) {
  this.isOutputRendered = isOutputRendered;
 }
 public String getDescription() {
  return description;
 }
 public void setDescription(String description) {
  this.description = description;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getProduct() {
  return product;
 }
 public void setProduct(String product) {
  this.product = product;
 }
 public String getProductManager() {
  return productManager;
 }
 public void setProductManager(String productManager) {
  this.productManager = productManager;
 }
}


Above approach encapsulates data and also separates data and logic.

All code above is tried and tested with salesforcec summer'12 release. Let me know if you are having any issue implementing above design.

No comments:

Post a Comment