Salesforce | Force.com, apex, triggers, SOQL, eclipse, visualforce, flows
apex, visual force, apex triggers, apex jobs, custom object, standard object, SOQL, components, etc.
Monday 27 June 2016
Wednesday 9 March 2016
Two duplicate error messages on VF page
Issue: When custom/standard input fields are used with custom label and are required on visualforce page, then pageMessages shows two error messages. Lets check below example with code:
When you need to change standard label with custom one on VF page then page message will show two error instead of one as stated above.
Solution: Explicitly change label on load client side using jquery. It requires:
Click here to see working demo, Happy Coding :) !!
<apex:page StandardController="Contact" sidebar="false" showHeader="false" >
<apex:form >
<apex:pageBlock title="Complete below form">
<apex:pageMessages />
<apex:pageBlockButtons location="bottom">
<apex:commandButton action="{!save}" value="Save" />
</apex:pageBlockButtons>
<apex:pageBlockSection title="Confirm Below Fields">
<apex:inputField label="Your Birth Date" value="{!contact.Birthdate}" required="true"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
When you need to change standard label with custom one on VF page then page message will show two error instead of one as stated above.
Solution: Explicitly change label on load client side using jquery. It requires:
- Custom Label -> to provide ease to user to set desired custom label.
- div element with static id -> to wrap <apex:pageMessages /> within so that it can be identified at client side.
- jQuery -> to browse through the html elements on client side(browser).
The VF page code:
<apex:page StandardController="Contact" sidebar="false" showHeader="false" >
<script src="https://code.jquery.com/jquery-2.2.0.min.js" />
<apex:form >
<apex:pageBlock title="Complete below form">
<div id="errorPanel">
<apex:pageMessages />
</div>
<apex:pageBlockButtons location="bottom">
<apex:commandButton action="{!save}" value="Save" />
</apex:pageBlockButtons>
<apex:pageBlockSection columns="1" title="Confirm Below Field">
<apex:pageblockSectionItem>
<apex:outputLabel value="{!$label.Contact_BirthDate}"></apex:outputLabel>
<apex:inputField value="{!contact.Birthdate}" required="true"/>
</apex:pageblockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
<script>
window.onload = changeErrorLabels();
function changeErrorLabels(){
var msgEle = $("#errorPanel").find(".messageText");
var replacedHtml = msgEle.html().replace('Birthdate','{!$label.Contact_BirthDate}');
msgEle.html(replacedHtml);
}
</script>
</apex:page>
The above solution once implemented provides flexibility to user to change/modify custom label with desired label text that have same error message labels on VF page.
Click here to see working demo, Happy Coding :) !!
Thursday 25 February 2016
Apex Readable Code - Best Practices
Code readability is a universal
subject for computer programming that should be learned as developers. This article
is for Salesforce Developers and focuses on 8 most important best practices considered
when writing readable code using Apex.
The eight most important practices
are:
1. Class
Documentation - Every class/trigger should have proper documentation
stating the purpose of class with its author.
2. Commenting
- Programmers use comments to annotate a program and help the reader (or
grader) understand how and why your program works. Comments should describe
what or why you are doing something, rather than how. Eg,
i++;
// increment i by one
·
Above comment how to increment rather why. So, do not write
comments that restate the code.
·
Update the comments when you update the code.
3. Consistent
Indentation & Whitespace – When you are part of a team or if you
are contributing code to a project, you should follow the existing style that
is being used in that project.
·
Don't put more than one statement on a line.
·
Use blank lines to separate your code into logical sections.
·
Put a space between all binary operators (e.g., <=, =, +) and
their operands. One possible exception is to emphasize precedence, like z = a*b
+ c*d
·
Put a space after each comma in an argument list.
·
Do not put spaces before a semicolon.
·
Do not put spaces between a method name and its left parenthesis.
·
Include blank lines to improve readability by grouping blocks of
related code.
·
Avoid code horizontal line longer than 100 characters (approx.,
it depends).
4. DRY
Principle - DRY stands for “Don't Repeat Yourself”. The purpose for most
applications (or computers in general) is to automate repetitive tasks. This
principle should be maintained and same piece of code should not be repeated
over and over again. Let say you need to check duplicate in a list on 2 VF
pages or in 2 triggers then it’s good to have a static method in utility class which
can be reused from anywhere within application.
5. Overcome
Apex Line Characters Limit –
·
When populating map in apex in traditional style:
·
Populating map in apex, optimized style from 6 lines to 4 lines:
·
Use of ternary operator instead of if-else where possible,
6. Consistent
Naming - There are some general principles when
choosing names for your variables, methods, and classes.
·
Use meaningful names that convey the
purpose of the variable. Choose names that are easy to pronounce, and avoid
cryptic abbreviations. For example, use wagePerHour or hourlyWage instead of wph. Use polygon instead of p or poly or pgon.
·
Be consistent.
·
Name boolean variables and
methods so that their meaning is unambiguous, e.g., isPrime or hasValue.
·
Use shorter names (e.g., i) for short-lived
variables and loop-index variables. Use more descriptive names for variables
that serve an important purpose.
·
Avoid generic names like foo or tmp and meaningless
names like fred. Use terminology from the application domain when
possible.
·
Name a constant by its meaning, not its
value, e.g., name your variable DAYS_PER_WEEK instead of SEVEN.
7. Avoid
Deep Nesting – Too many levels of nesting can make code harder to read and
follow.
For the sake of readability, it is usually
possible to make changes to your code to reduce the level of nesting:
8. Capitalize
SOQL Special Words – It is a good idea to capitalize SOQL special words. Even
though SOQL special words and function names are case insensitive, it is common
practice to capitalize them to distinguish them from other variables and
keywords.
Thursday 26 June 2014
Parse zipped XML files on visualforce page
Salesforce doesn't have direct method to read files. We can do it either by external service written in Java/.Net or using javascript.
We will be discussing to parse data coming in zipped XML over http from 3-party API and populate data in salesforce. Basically, there were three main tasks:
Task 3:
Task 2:
Key points to remember:
We will be discussing to parse data coming in zipped XML over http from 3-party API and populate data in salesforce. Basically, there were three main tasks:
- Collect http reponse from API in form of zipped xml.
- Unzip that response and get xml string out of it.
- Parse xml string to insert data.
Main focus of this blog is to accomplish Task 2 but first let see the key points for tasks 1 & 3:
Task 1:
- You just need to call response.getBodyAsBlob() when ever response is in form of file.
- Then, you need to convert bolb into string using code syntax:
String xmlzippedFile = EncodingUtil.base64Encode(res.getBodyAsBlob());
Task 3:
- If your XML string contains <![CDATA[value]]> tag then make use of XmlStreamReader class.
- If not, then you can either use Document class or XmlStreamReader class.
Task 2:
Main task to unzip xml file, the steps to achieve are mentioned below:
- Add jZip.js file to static resource (download)
- Add inflate.js file to static resource. (download)
- Open notepad, paste below code and save as file.js file and upload to static resource.
var filearr = []; /* Main unzip function */ function unzip(zip){ model.getEntries(zip, function(entries) { entries.forEach(function(entry) { model.getEntryFile(entry, "Blob"); }); }); } //model for zip.js var model = (function() { var URL = window.webkitURL || window.mozURL || window.URL; var acount = 0; var bcount = 0; //compile a list of file extensions and content types var mapping = { "pdf":"application/pdf", "zip":"application/zip", "rar":"application/rar", "json":"application/json", "mid":"audio/mid", "mp3":"audio/mpeg", "bmp":"image/bmp", "gif":"image/gif", "png":"image/png", "jpg":"image/jpeg", "jpeg":"image/jpeg", "svg":"image/svg+xml", "xml":"text/xml" } return { getEntries : function(file, onend) { zip.createReader(new zip.BlobReader(file), function(zipReader) { zipReader.getEntries(onend); }, onerror); }, getEntryFile : function(entry, creationMethod, onend, onprogress) { acount++; var writer, zipFileEntry; function getData() { entry.getData(writer, function(blob) { bcount++; filearr.push(blob); if(acount == bcount){ //your vf page method waitForProcess(); } }, onprogress); } var extension = entry.filename.substring(entry.filename.indexOf(".")+1); var mime = mapping[extension] || 'text/plain'; writer = new zip.BlobWriter(mime); getData(); } }; })();
- Create a VF page and include reference to jZip.js and file.js
- Create a button on VF page to invoke a javascript remoting method which returns a string from Task 1. (Or you can also place a input file element with button if you just want to upload zipped from client machine).
<!-- place after page start--> <meta charset="utf8" /> <apex:includeScript value="{!URLFOR($Resource.jQuery, '')}"/> <apex:includeScript value="{!URLFOR($Resource.zip, '')}"/> <script> $( document ).ready(function() { //Call loading requestFile(); }); function base64toBlob(base64Data, contentType) { contentType = contentType || ''; var sliceSize = 1024; var byteCharacters = atob(base64Data); var bytesLength = byteCharacters.length; var slicesCount = Math.ceil(bytesLength / sliceSize); var byteArrays = new Array(slicesCount); for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) { var begin = sliceIndex * sliceSize; var end = Math.min(begin + sliceSize, bytesLength); var bytes = new Array(end - begin); for (var offset = begin, i = 0 ; offset < end; ++i, ++offset) { bytes[i] = byteCharacters[offset].charCodeAt(0); } byteArrays[sliceIndex] = new Uint8Array(bytes); } return new Blob(byteArrays, { type: contentType }); } function requestFile() { var param = 5; //set your param to pass in method Visualforce.remoting.Manager.invokeAction( '{!$RemoteAction.APEX_PAGE_CONTROLLER_NAME(GLOBAL).methodName}', param, function(result, event){ if (event.status) { //call unzip method unzip(base64toBlob(result, '')); } else if (event.type === 'exception') { console.log(event.message); } }, {escape: true} ); } var xmlStrResult = []; var isExecuted = false; var timerVal; //your vf page method function waitForProcess(){ console.log('call timer'); timerVal = setInterval('prepareXMLString()', 10); } function prepareXMLString() { if(!isExecuted){ $.each(filearr, function(index, file){ var reader = new FileReader(); // Create a FileReader object reader.onload = function() { // Define an event handler try { var xmlDoc = $.parseXML(reader.result); var xmlString = (new XMLSerializer()).serializeToString(xmlDoc); xmlStrResult.push(xmlString); // Display file contents }catch(err) { //TODO } } reader.readAsText(file); isExecuted = true; }); } if(xmlStrResult.length != 0){ clearInterval(timerVal); $('#showData').val(xmlStrResult[0]); console.log('Done'); } } </script> <apex:pageBlock > <apex:pageBlockSection columns="1" title="Your XML string"> <apex:pageBlockSectionItem > <textarea id="showData" name="showData" rows="30" cols="150"> Please wait.... </textarea> </apex:pageBlockSectionItem> </apex:pageBlockSection> </apex:pageBlock> <apex:includeScript value="{!$Resource.file}" loadOnReady="true"/> <!-- place before page ends-->
Key points to remember:
- Remoting is required, when you get file from apex controller as http response or from attachment/static resource.
- In case of input file element, pass file directly to unzip() method.
Happy coding :) !!
Tuesday 16 April 2013
Salesforce based on MVC
Blog discuss very basic understanding of MVC with respect to Salesforce.
MVC
- Front End(User Interface) - View
- Entity/ Object to hold data - Model
- Business logic - Controller
In simple terms, Controller fetches the data from data source and populates Model(object) to display it on View.
Salesforce
- Front End(User Interface) - Visual Force page, Native page layout.
- Entity/ Object to hold data - Salesforce Object (standard, custom)
- Business logic - Apex Class behaves as controller.
Subscribe to:
Posts (Atom)