Category Archives: Visualforce

Sortable, searchable table with pagination using knockout.js in Salesforce

This is a demo using knockout.js to create a table for listing records of any object custom, standard or combinations of data from multiple objects.  The table is sortable and searchable using a typeahead search field.  It also includes a dropdown to limit the number of records visible as well as pagination.

This is what it looks like in its most basic styling:

This is the link to the working demo

 

This is the component that holds the knockout code:

This is the controller to retrieve the records using a remote action:

The visualforce page:

 

Get and pass date from Controller and pass to knockout

Javascript remote on site:

Visualforce.remoting.Manager.invokeAction(
  	'{!$RemoteAction.ApplicationController.getStudentInfo}',    
  	    function(student){                        	                        	                       	                                                                              		
    		Application.studentLastName(student.LastName); 
    		Application.studentFirstName(student.FirstName);
    		Application.studentPhone(student.Phone);
    		Application.studentAltPhone(student.OtherPhone);
    		Application.studentEmail(student.Email);   		
    		Application.studentHomeAddress(student.MailingStreet);			    		
    		Application.studentCity(student.MailingCity);			    		
    		Application.studentZip(student.MailingPostalCode);
    		Application.studentCountry(student.MailingCountry);
    		if(student.Birthdate != null){
    			var dob = normalizeDate(student.Birthdate);
	    		var dobAlt = normalizeDate2(student.Birthdate);
	    		Application.studentDOB(dob);
	    		document.getElementById('studentDOB_alternate').value = dobAlt;
	    }
  	},{escape : false});

Script to convert date from controller to mm-dd-yyyy

function normalizeDate(dateVal){ 
	mydate = new Date(dateVal);
    data = new Date(mydate -  mydate.getTimezoneOffset() * 60000);
    var d = mydate.getDate()+1;
    var m = mydate.getMonth()+1;
    var y = mydate.getFullYear();
    return (m<=9?'0'+m:m) +'-' + (d<=9?'0'+d:d)+'-' + y;		
}

Script to convert date from controller to yyy-mm-dd to send back to controller

function normalizeDate2(dateVal){ 
	mydate = new Date(dateVal);
    data = new Date(mydate -  mydate.getTimezoneOffset() * 60000);
    var d = mydate.getDate()+1;
    var m = mydate.getMonth()+1;
    var y = mydate.getFullYear();		    
    return y + '-' + (m<=9?'0'+m:m) +'-' + (d<=9?'0'+d:d);		
}

Knockout send to controller

self.goToParentSection = function(){
    			if (studentInfoValidation().length === 0) {		
					var parentIsEdit = self.parentIsEdit();
					var studentDetails = {
						representativeId : self.representativeId(),						
						applicationId : self.applicationId(),										
						studentFirstName : self.studentFirstName(),
						studentLastName : self.studentLastName(),
						studentDOB : (j$('#studentDOB_alternate').val()),
						studentPhone : self.studentPhone(),
						studentOtherPhone : self.studentAltPhone(),
						studentEmail : self.studentEmail(),
						studentCountry : self.studentCountry(),
						studentHomeAddress : self.studentHomeAddress(),
						studentCity : self.studentCity(),
						studentState : self.studentState(),
						studentZip : self.studentZip(),
						studentId : self.studentId(),
						studentInfoComplete : self.studentDetailsComplete(),
						householdId : self.householdId()																																	
					}
					Visualforce.remoting.Manager.invokeAction(
	                	'{!$RemoteAction.ApplicationController2.studentInfo}',studentDetails,   
	                        function(results){                        	
	                        	self.studentId(results.Id);	                            				                
	                        },{escape : false});
																
				}
				else {
		            alert('Please check your submission.');
		            studentInfoValidation.showAllMessages();
		        }		        					
			}			

Controller

@RemoteAction
    public static object studentInfo(Map<string, string> studentDetails){
		Date dt = Date.valueOf(studentDetails.get('studentDOB'));  
        studentId = studentDetails.get('studentId');
		Contact studentToUpdate = [SELECT id,AccountId, Name FROM Contact WHERE Id =: studentId];
		string contactRecordTypeId;    		
		RecordType rt = [select Id, Name from RecordType where DeveloperName = 'Student_Master' and SobjectType = 'Contact' limit 1];
		contactRecordTypeId = rt.Id;
		studentToUpdate.RecordTypeId = contactRecordTypeId;
		studentToUpdate.LastName = studentDetails.get('studentLastName');
		studentToUpdate.FirstName = studentDetails.get('studentFirstName');
		studentToUpdate.Phone = studentDetails.get('studentPhone');
		studentToUpdate.OtherPhone = studentDetails.get('studentOtherPhone');
		studentToUpdate.Email = studentDetails.get('studentEmail');   		
		studentToUpdate.MailingStreet = studentDetails.get('studentHomeAddress');  		
		studentToUpdate.MailingCity = studentDetails.get('studentCity');
		studentToUpdate.MailingState = studentDetails.get('studentState');
		studentToUpdate.MailingPostalCode = studentDetails.get('studentZip');
		studentToUpdate.MailingCountry = studentDetails.get('studentCountry');    		
		studentToUpdate.BirthDate = dt;    			
		
		update studentToUpdate;

		return studentToUpdate;    
	}

Visualforce page with datepicker


	

Override a page for some, but not all, users

Some of your users should use a custom Visualforce page, while others should use a standard Salesforce.com page.To override the Account tab with a Visualforce page for most of your users, but send users with the “System Administrator” profile to the standard Salesforce.com Account home page:

  1. Create a Visualforce page called conditionalAccountOverride.
    • Click Setup | Develop | Pages.
    • Click New.
    • In the label field, enter Override the Account Page for Most Users.
    • In the name field, enter accountOverride.
    • In the description, enter This page will display for all users, except System Administrators, when they click the Account tab.
    • In the editor, enter the following markup:
<apex:page action=
  "{!if($Profile.Name !='System Administrator', 
    null, 
	urlFor($Action.Account.Tab, $ObjectType.Account,
	null, true))}"
  standardController="Account" 
  recordSetVar="accounts" 
  tabStyle="Account">

  <!-- Replace with your markup -->  
	
  This page replaces your Account home page for 
  all users except Administrators.
</apex:page>
    • Click Save.

2. Set the page level security to allow all users to view the page.

    • Click Security for the page you just created.
    • Select all the profiles that will be using this page in the Available Profiles list and click Add to add them to the Enabled Profiles list.
    • Click Save.

3. Create an override that directs users to your new page.

    • Click Setup | Customize | Accounts | Buttons and Links.
    • In the Standard Buttons and Links list, click Override for the Accounts Tab.
    • Set the content type to Visualforce Page.
    • From the Content Name drop-down list, select conditionalAccountOverride.
    • Click Save.

This solution uses the action attribute on the apex:page component to test the user’s profile. Using the action attribute is a good way to ensure an action is taken when the page loads. If instead of limiting the standard page to a particular group of users, you want to limit the override to a particular group of users, such as all “Marketing Users” and “Solution Managers,” you need to create a controller extension. To override the Account tab with a custom Visualforce page only for users with the “Marketing User” or the “Solution Manager” profile:

  1. Create a Visualforce page called standardAcctPage.
    • Click Setup | Develop | Pages.
    • Click New.
    • In the label field, enter Override the Account Page for Most Users.
    • In the name field, enter standardAcctPage.
    • In the description, enter This page will display for all users, except Marketing Users and Solution Managers, when they click the Account tab.
    • In the editor, enter the following markup:
<apex:page standardController="account" extensions="overrideCon" action="{!redirect}">
  <apex:detail/>
</apex:page>

This page overrides your current Account home page. It uses a controller extension to test the user profile. If the user is a “Marketing User” or “Solution Manager,” they are redirected to a different page.

2. Using the procedure in step 1, create a second Visualforce page called customAcctPage:

<apex:page standardController="account">
  <h1>Override Account page for two profiles</h1>
  <apex:detail />
</apex:page>

This is the page that only the “Marketing Users” and “Solutions Managers” will see. They only get to this page through redirection.

3. Grant access to both pages for all profiles.

    • Click Security for the each of the pages you just created.
    • Select all the profiles that will be using this page in the Available Profiles list and click Add to add them to the Enabled Profiles list.
    • Click Save.

4. Create a controller extension called overrideCon.

    • Click Setup | Develop | Apex Classes.
    • Click New.
    • In the editor, add the following content:
public class overrideCon {
   String recordId;
   
public overrideCon(ApexPages.StandardController 
       controller) {recordId = controller.getId();}

public PageReference redirect() {
  Profile p = [select name from Profile where id = 
			   :UserInfo.getProfileId()];
  if ('Marketing User'.equals(p.name) 
	  || 'Solution Manager'.equals(p.name)) 
	  {
	   PageReference customPage =  Page.customAccountPage;
	   customPage.setRedirect(true);
	   customPage.getParameters().put('id', recordId);
	   return customPage;
	  } else {
		  return null; //otherwise stay on the same page  
	
	  }
   }
}
    • Click Save

5.  Create an override that directs users to the standardAcctPage page when they click on the Accounts tab.

    • Click Setup | Customize | Accounts | Buttons and Links.
    • In the Standard Buttons and Links list, click Override for the Accounts Tab.
    • Set the content type to Visualforce Page.
    • From the Content Name drop-down list, select standardAcctPage.
    • Click Save.

When a user clicks on the Account tab, if their profile is “Marketing User” or “Solution Manager” the controller extension will automatically redirect them to the customAcctPage.

 

Redirect to external URL using JavaScript on Visualforce page

<div class="col-md-4 col-sm-4 col-xs-12 loginBox" >                
    <div>
        <h3 style="text-transform:uppercase;">Customers</h3>
    </div>
    <div>
        <h2 class="loginH2">I have a login</h2>
    </div>
    <div id="div1" class="div1">
        <p1>You are a customer submitting a claim for your vehicle or property.</p1> 
    </div>
    <div class="loginButton">
        <input type="submit" value="login"  onclick="toMyWeb(); return false;"/>
    </div>
    <script>
        function toMyWeb(){
            window.location.href="http://www.MyWeb.com";
        }
    </script>
</div>    

How to: Visualforce Javascript Remoting

If you have done some Salesforce development, you have probably seen or heard of Visualforce Javascript Remoting.  If you haven’t heard of it, it is basically a way within Salesforce to call methods in a class via javascript.

You might be thinking to yourself “Hey, that sounds cool but why would I want to do that?”.  Well, there are a number of reasons.

No forms!
First of all, you are not required to use forms, Apex or otherwise.  This eliminates the need to keep viewstate.  By not keeping viewstate you are not passing or storing all of that data for the controller calls.  Your calls to the controller have a small footprint and become very efficient.  This is especially useful in mobile web development.

Blazing!
This leads to the second reason why you would want to use remoting, speed.  It is by far the fastest way of calling controller code and passing data to and from the page.  You are able to ensure that you are only passing the data you need each time you make a call.  Salesforce also bundles multiple subsequent calls by default with no work by you which also improves speed.

Asynchronous
The third reason why you might want to use remoting is because it is asynchronous.  Since it is asynchronous, you can load the initial page and data for the page and after that is all loaded you can start to lazy load data for the page that might not be prevalent for the inital load.  You can even use this method to start loading data for pages the user hasn’t even hit yet.  An example of this would be to load the first page and if there is a second page that you know if visited often you can load that in the background so if the user does switch to that second page all the data will be available which leads to an awesome user experience.

You are probably thinking, “This sounds awesome!  Why don’t I use this for everything?”.  Well, while it is pretty awesome it does take extra time to develop for and you also need to change how you develop and thinking about the flow of the page.  Since you aren’t using forms and there is no viewstate associated with it, you have to manage the state of the page on the client side.  On the other hand, there is nothing that says you can’t do a hybrid of using remoting with the standard MVC design paradigm with forms.  These are all things you need to consider when determining your design.  Remoting is just another tool in your belt.

So how do you use remoting?  It is actually pretty easy to do.  The definition for making a call in JS to a class is:

[namespace.]controller.method(
    [parameters…,]
    callbackFunction,
    [configuration]
);

That looks simple enough but what does it look like in practice?  Here you go:

MyController.methodOnMyController(
    firstParameter,
    secondParameter,
    function(results, event) {
        if(event.type === 'exception'){
            console.log("exception");
            console.log(event);
        }else if(event.status){
            $j.each(results, function(i, result){
                doSomethingWithTheResult(result);
            });
        }else{
            console.log(event.message);
        }
    }
);

This code is assuming I have a class called MyController and MyController has a method on it called methodOnMyController that takes two parameters.  If you have done ajax calls in jQuery this will look very familiar.  After the parameters, you have your callback function.  The callback function takes the results of the method call as well as the event object which has information on how the remoting call went.  If there is an exception it tells you so you can handle that in your JS otherwise you simply handle the results from the method call.

That’s all there is to it.  You can do what you will with the data depending on what you are trying to accomplish.  The nice thing about it is you can return standard and custom object as well as your own wrapper classes and reference the data just the same.

To complete the code on the controller, simply declare a public method in a public class as a remote action and make it static like so:

@RemoteAction
public static List<MyObject> methodOnMyController(String firstParemeter, String secondParameter){
    return new List<MyObject>();
}  

 

I hope this helps you will understanding remoting.  If you have any questions feel free to leave them in the comments below.  If you would like to learn more about JS remoting check out Salesforce’s docs.

Originally from :  Craig Isakson-Sundog Blog

Using the !Case Logic Function

In the previous post I changed the image on one page depending on the referring page but that was an all or one situation.   I had a situation where there were mutiple orgs referring to one Visualforce page that needed a different logo image for each.  Instead of using an IF/ELSE statement I used the CASE logic function. The documentation states this for the use of this function:

CASE(expression,​value1, result1, value2,​result2,…,​ else_result) and replace expression with the field or value you want compared to each specified value. Replace each value and result with the value that must be equivalent to return the result entry. Replace else_result with the value you want returned when the expression does not equal any values.

This was a little tricky because it doesn’t state specifically if the values needed double quotes or single quotes(it didn’t work until I put in double quotes btw).  This is what it finally looked like:

<img  src="{!CASE($CurrentPage.parameters.SrcOrg, "orgOne", URLFOR($Resource.sourceZip, '/images/orgOne.png'),
            "orgTwo", URLFOR($Resource.sourceZip,'/images/orgTwo.gif'),
            "orgThree", URLFOR($Resource.sourceZip,'/images/orgThree.jpg'), 
            "orgFour", URLFOR($Resource.sourceZip,'/images/orgFour.gif'), 
            "orgFive",URLFOR($Resource.eFNOLpage,'/images/orgFive.jpeg'), 
            URLFOR($Resource.sourceZip,'/images/default.jpg'))}"   />
           

Change Logo Image Based on Referring Site With Button onclick

To change the logo image on a page based on the referring page allows for appropriate branding depending on where the user came from to get to the app.  In the Visualforce page the <div> including the image has code like this:

<div class="col-lg-6 col-sm-5">
        <img  style="max-width:100px; margin-top: -7px;" src="{!IF( $CurrentPage.parameters.SrcOrg == 'MyOtherOrg',$Resource.MyOtherLogo,
URLFOR($Resource.my_logo_imgs,'MyLogoImg.jpg'))}"   />
</div>

note: the images are static resources by themselves and not in a zip file.

The buttons that are on the sites have this code:

<div class="row">
      <div class="col-sm-12 text-center">
          <apex:commandbutton styleClass="btn btn-primary" value="MyOrg.com" 
                    onclick="window.location='/apex/myMainPage?srcOrg=myOrg'; return false;"/>
     </div>
    </div>
    <div class="row">
      <div class="col-sm-12 text-center">
          <apex:commandbutton styleClass="btn btn-primary" value="MyOtherOrg.com" 
                    onclick="window.location='/apex/eFNOL0106?srcOrg=myOtherOrg'; return false;"/>          
      </div>
    </div>

It doesn’t matter what the original org button uses to append the url because the code that changes the logo only looks for “myOtherOrg” in the url(everthing else will default to the myLogoImg image.

 

 

Uploading a Document using Visualforce and a Custom Controller

Create a Visualforce page that references a controller (documented below). Note the enctype attribute on the <apex:form> tag. This Visualforce page uses only the fields necessary for uploading a document but can be expanded to include field for other records or documents in the process.

<apex:page controller="FileUploadController">
  <apex:sectionHeader title="Visualforce Example" subtitle="File Upload Example"/>
 
  <apex:form enctype="multipart/form-data">
    <apex:pageMessages />
    <apex:pageBlock title="Upload a File">
 
      <apex:pageBlockButtons >
        <apex:commandButton action="{!upload}" value="Save"/>
      </apex:pageBlockButtons>
 
      <apex:pageBlockSection showHeader="false" columns="2" id="block1">
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="File Name" for="fileName"/>
          <apex:inputText value="{!document.name}" id="fileName"/>
        </apex:pageBlockSectionItem>
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="File" for="file"/>
          <apex:inputFile value="{!document.body}" filename="{!document.name}" id="file"/>
        </apex:pageBlockSectionItem>
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="Description" for="description"/>
          <apex:inputTextarea value="{!document.description}" id="description"/>
        </apex:pageBlockSectionItem>
 
        <apex:pageBlockSectionItem >
          <apex:outputLabel value="Keywords" for="keywords"/>
          <apex:inputText value="{!document.keywords}" id="keywords"/>
        </apex:pageBlockSectionItem>
 
      </apex:pageBlockSection>
 
    </apex:pageBlock>
  </apex:form>
</apex:page>

Create an Apex class that behaves as the controller in the Visualforce page. The upload() method is key.

public with sharing class FileUploadController {
 
  public Document document {
    get {
      if (document == null)
        document = new Document();
      return document;
    }
    set;
  }
 
  public PageReference upload() {
 
    document.AuthorId = UserInfo.getUserId();
    document.FolderId = UserInfo.getUserId(); // put it in running user's folder
 
    try {
      insert document;
    } catch (DMLException e) {
      ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error uploading file'));
      return null;
    } finally {
      document.body = null; // clears the viewstate
      document = new Document();
    }
 
    ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO,'File uploaded successfully'));
    return null;
  }
 
}

Visualforce takes care of all the hard work by updating the document from the file that’s uploaded. All your controller class needs to do is store it. If you would like to attach the document to a specific record you will need to use the Attachment object instead of the Document object.

Notes

Make sure you take a look at the finally block in the controller code above. The finally block always executes when the try block exits regardless if an error occurs or not. You need to ensure you clear out document’s body (document.body = null) so that the blob is not automatically included in the serialized image of the controller. If you do not clear out the body, you’ll get the following view state error: “Maximum view state size limit (128K) exceeded. Actual viewstate size for this page was…”