Showing posts with label Visualforce. Show all posts
Showing posts with label Visualforce. Show all posts

Monday, 14 September 2015

Lightning Experience Trailblazing!!!

In a special global broadcast, Salesforce recently launched the 'The new Salesforce'. This new Salesforce came in the form of the 'Lightning Experience', a new, responsive, crisp UI, that takes your existing Salesforce data and presents it in a much more modern graphical manner. It's responsive, and aims at providing a unified experience and appearance across all your devices, from watch to phone to tablet to desktop. Check out the introduction and demo video from the Salesforce website.

This announcement was great, it left users looking forward to getting started with the new interface. However, as a developer during this initial presentation I had a lot of questions; What does this mean for all the Visualforce I've written? How do I make my pages look like they belong in Lightning? Do I need to build two versions of everything (Lightning Exp. and Classic) in order for stuff to work for everyone? Are there any kind of code techniques and tweaks I use at the moment that won't work anymore?

Fortunately though, answers weren't far behind, as Salesforce Developers released several new Trailhead learning tracks that address these questions, respond to common concerns and let you get hands on with building some Lightning Components for the new UI. For those have never used Trailhead before, it's an amazing learning tool that provides Salesforce users from all walks of life (CRM User, Admin, Developer) with exercises, both written and practical, for learning more about how to make the most out of Salesforce. There are four new trails (with shiny badges) to get your teeth stuck into:


The two admin trails guide you through the process and best practice of moving your existing Salesforce Classic organisation over to Lightning Experience, and explore how to use the basic features of the new UI once you have made the switch. The Sales Rep trail takes you through the experience from an end user perspective, showing how to use the new features to make better sales. The developer trail includes elements of the admin trails, but also explores how to manage your existing custom coded functionality and build new apps effectively in the new UI.

Although all four are definitely worth doing no matter what your role is, as a developer the one trail your should definitely tackle, unsurprisingly, is the Lightning developer track. Taking a closer look, the track consists of 5 different modules, each of which provide a different view of the Lightning Experience and answer different questions you may have.

Name Content Questions it answers


Lightning Experience Basics
An Overview of the new UI, and what it means to both new and existing Salesforce organisations. Includes tips on how to conduct a gap analysis when considering making the switch to the Lightning Experience, before turning it on.
  • What is Lightning Experience?
  • How do I know if my organisation is ready to make the switch?
  • How do I turn it on?


Lightning Experience Development
Looks at how your existing use of Visualforce will be affected when using the Lightning Experience. Explains what elements will continue to work, those that do not (for now) and what elements will need reviewing.
  • Will my existing Visualforce pages still work in Lightning Experience?
  • Are there any existing paradigms and features no longer supported if I make the switch?
  • How does this affect my products as an ISV?


Visualforce & Lightning Experience
This unit goes into further detail about the relationship between Visualforce content and the Lightning Experience container it will be presented in. It also contains recommendations for styling and methods of identifying if a user is accessing the Page through each of the different UIs.
  • How will Visualforce content be presented in Lightning from a technical perspective?
  • How can I prepare a Visualforce Page for use in both Salesforce Classic and Lightning Experience simultaneously?
  • Will my Page actions and Visualforce navigational methods still work?


Lightning Components
An introduction to the development of reusable Lightning Components. This is not a new unit, but with the introduction of the Experience, has been given extra importance and greater context.
  • How do I build and style a basic Lightning Component?
  • How do I pass attributes between different Components?
  • How do I get Lightning Components to run Apex Code?


Lightning Design System
Introduced alongside the Lightning Experience, the Lightning Design System is a tool that aids in the design of Pages to make them look and feel right at home inside the new UI. This unit explores how to use the tool and how to take your app design to the next level.
  • What is the Lightning Design System and why should I use it?
  • How do get my existing apps and pages to look and behave like the rest of the Lightning Experience?
  • How can I include some cool Lightning design elements such as icons and avatars easily into my Pages?

As you can see, the trail covers a lot of ground; it includes 30 individual units, and takes around 10 hours in total to complete, so prepare to lose a few evenings or a weekend, but trust me, it's totally worth it!

From a personal point of view, what I really like about the Lightning Experience developer trail is the practical and honest way it presents the new Lightning Experience, and really gets down to the point in terms of what developers need to know. It's not a sales pitch, shouting "Lightning Experience is here, there is no effort in transition from Salesforc Classic and it makes all your existing stuff magically more amazing!". It is a frank explanation of what will definitely work, what won't, changes you will have to potentially make to existing Visualforce Pages and how to effectively develop a transition strategy between Classic and Lightning.

I also think the inclusion of the unit based around the new Design System is a great idea. In the past, I have always found it challenging to get started with designing content for mobile and Salesforce1, simply because the appearance of anything I developed didn't seem to fit 100% correctly into the look and feel of the app as a whole. The Design system gives you that boost to start developing crisp looking custom content for both mobile and content with the new UI without the hassle and instability of large quantities of highly customised CSS.

From the trail content, it makes it really obvious that Salesforce have spent a lot of time working out the best way to introduce the Lightning Experience to existing developers. It addresses a lot of the concerns developers have, and covers both the management and adaptation of what you already have, whilst also illustrating the best way to build new apps as part of the new exciting UI.

One of the only slight frustrations of the trail is that is it largely tested through questions and answers rather than practical assignments. Those are always the trails that I enjoy the most. But this is only a short term gripe, as I have no doubt more practical exercises will emerge after the feature is GA.

In summary it's a great way to introduce yourself to the new look Salesforce before it storms into orgs as part of Winter '16. So, if you haven't already, get to Trailhead and get Trailblazing! Don't forget to show off those badges!

Tuesday, 7 August 2012

Visualforce Component that creates a picklist without a -none- value

About a year and a half ago, when I was relatively new to the Force.com platform, I devised a way to create a picklist value selector with a '-none-' value for a field that could be placed on to a Visualforce page, to prevent users from not setting a value for a picklist field.

A question was posted in that blog entry that asked if it was possible to have two picklists for different fields on the same Visualforce page. I replied with an answer that was basically "write the code out twice". While this works, its not exactly re-usable or easy to maintain.

Being a big fan of Visualforce components, I set about converting the no '-none-' picklist code into a re-usable component that can be placed onto any number of pages, and used in different applications easily. I found that this was possible by using the describe object and describe field calls.

The component I have created is called InputPicklistNoNone. It has two attribute arguments that have to be defined when using it in a Visualforce Page:
  • Value: This is the reference for the variable you want to assign the picklist selection to. It is much like the value attribute for most Visaulforce input components, such as apex:inputField and apex:inputText.
  • Field: This is the API reference of the picklist field you want to extract the possible values from. If this value points to an invalid field, an error message will be added to the page.
Below is the component code, and sample page and controller code to show how the component can be used. This is just a simple example using the component in a Visualforce Page and a standard controller with an extension. The component is flexible, it can be used with custom controllers and the value it populates can be an object field or a string variable.

Component Code:
<apex:component controller="InputPicklistNoNoneController">
  <apex:attribute name="value" required="true" type="String" 
   description="The variable the selected option will be assigned to"/>
  
  <apex:attribute name="field" assignTo="{!fieldName}"    
   required="true" type="String" 
   description="The picklist field that forms the basis of the input"/>

  <!--If the value is empty, then set it to be equal to the default 
      value from the schema description-->

  <apex:variable var="value" value="{!defaultOption}" 
   rendered="{!ISNULL(value)}"/>

  <apex:selectList size="1" value="{!value}">
    <apex:selectOptions value="{!options}"/>
  </apex:selectList>
</apex:component>

Component Controller:
public class InputPicklistNoNoneController 
{
    public String             defaultOption {get;set;}
    public List<SelectOption> options       {get;set;}
    public String             fieldName
    { 
        get;
        set 
        {
            fieldName = value;
            options = new List<SelectOption>();
            List<String> fieldNameSplit = fieldName.split('\\.');
        
            Schema.DescribeFieldResult picklistFieldDescription =
              Schema.getGlobalDescribe().get(fieldNameSplit[0])
              .getDescribe().fields.getMap()
              .get(fieldNameSplit[1]).getDescribe();

            for (Schema.Picklistentry picklistEntry:
                 picklistFieldDescription.getPicklistValues())
            {
                options.add(new SelectOption(pickListEntry.getValue(),
                                             pickListEntry.getLabel()));

                if (picklistEntry.defaultValue)
                {
                    defaultOption = pickListEntry.getValue();
                }
            }    
        }
    }    
}

Example Page:
<apex:page standardController="Invoice_Statement__c"
           extensions="InputPicklistNoNoneExampleExtension">
           
  <apex:sectionHeader title="No none picklist component example"/>
  
  <apex:form >
    
    <apex:panelGrid columns="2">
    
      
      <!-- The component can be used to populate an object field -->  
      <apex:outputText value="Status:"/>
      <c:InputPicklistNoNone value="{!Invoice_Statement__c.Status__c}" 
                             field="Invoice_Statement__c.Status__c"/>
    
      
      <!-- The component can also be used with a controller variable -->
      <apex:outputText value="Industry:"/>
      <c:InputPicklistNoNone value="{!myControllerVariable}"
                             field="Account.Industry"/>    
    
      <apex:commandButton value="Save" action="{!save}"/>
    
    </apex:panelGrid>
    
  </apex:form>  
</apex:page>

Example Controller Extension:
public class InputPicklistNoNoneExampleExtension 
{
    public String myControllerVariable {get; set;}

    public InputPicklistNoNoneExampleExtension(
           ApexPages.StandardController controller) {}

}

Screenshot of Example Page:

I am a big fan of how this has turned out, it keeps the functionality intact while making it easily adaptable for use on numerous variables on any number of pages, result! If you have any questions, or need some pointers on how to use it, then please add a comment below.

Tuesday, 14 February 2012

10 Easy steps to an improved default object home page

Around a year and a half ago, I wrote this rant of a post, outlining my frustrations with the default object home view pages. I am not alone in my frustration, an entry on the Salesforce ideas site to address this problem is proving quite popular. Given the apparent demand for an alternative, I started to look at the default landing page again and think about ways to improve it.



The common complaint concerning the page is that is has a very counter intuitive feel to it. When the page is loaded, our eyes are drawn straight away to view selection box in the top left hand corner and the list of objects directly below it. Where the confusion starts is that the selected view has no bearing on the displayed objects. The list of objects is the collection of items the user has recently viewed, edited or created, controlled by the tiny combo box on the far right hand side of the page.

The only way to access objects in the form of a view is to click the "Go" button by the view combo box. This page, as seen below, shows the data in a tabular form that is fully editable, where the sort order can be varied easily through clicking on the column headers. The view of the data can be changed easily through the same combo box as on the main screen.

After seeing the views page, I reasoned that I would much prefer this page as a home page for my objects than the standard view. There are no conflicting page elements, and I am not forced to see a recent items list, instead I have complete control over the view of the data.


After this realisation, I attempted to build a new homepage based on the tabular data summary that could be used for both standard and custom objects.

This actually turned out to be a lot simpler than anticipated, placing the enhanced list Visualforce component in a page provides a simple way to build view pages for an object. My only addition was a link to the default object page, just in case I ever required a recent view or one of the extended tool links. Assign this page to a tab, replace the original tab, and the user experience is much improved.

To set up a alternative default tab for a standard or custom object, simply follow these steps:

1) Open the current standard tab for your object, and note down the three characters at the mid section of the URL in the navigation bar of your internet browser. For example, Contact is '003' and Lead is '00Q'. I am going to create an alternative standard tab for the Account object, so the object code is '001'.



2) Create a new Visualforce page, by navigating to (Setup -> App Setup -> Develop -> Pages) and clicking on the New button. Call your new page "Alternative" + object label + "Homepage", such as "AlternativeContactHomepage" or "AlternativeMyCustomObjectHomepage". In the account example this would be "AlternativeAccountHomepage".


3) Erase the default body content created automatically by Salesforce, copy the following Visualforce code and place it in the body definition entry section. Don't save the page yet, a few attribute values within the tags need to be populated first.

<apex:page>
  <apex:sectionHeader title=""/>
  <apex:enhancedList type="" height="600" rowsPerPage="50"/>
  <br/>
  <apex:outputLink value="//o">
    See Recent Items / Extra Options
  </apex:outputLink>
</apex:page>


4) Inside the apex section header tag, enter the plural version of the object name. Enter the API name of the object in the type attribute of the apex enhanced list tag. Finally, place the object three character code recorded during step 1 in between the two forward slash characters in the value attribute of the apex output link.

For a standard object, such as Account, this page code should look like this:

<apex:page >
  <apex:sectionHeader title="Accounts"/>
  <apex:enhancedList type="Account" height="600" rowsPerPage="50"/>
  <br/>
  <apex:outputLink value="/001/o">
    See Recent Items / Extra Options
  </apex:outputLink>
</apex:page>

For a custom object, such as My Custom Object (with a three digit code of a01), the page code should look like this:

<apex:page >
  <apex:sectionHeader title="My Custom Objects"/>
  <apex:enhancedList type="My_Custom_Object__c" height="600" rowsPerPage="50"/>
  <br/>
  <apex:outputLink value="/a01/o">
    See Recent Items / Extra Options
  </apex:outputLink>
</apex:page>

To finish, click the Save button to save your new page.



5) Navigate to the tabs definition page (Setup -> App Setup -> Create -> Tabs). Click on the New button in the Visualforce Tabs section. Place the object name as it appears on the existing default object tab (i.e. Contacts or My Custom Objects). In the API name, enter the same. Choose a tab style (may I personally recommend Big Top or Saxophone :-D ), then click Next.



6) On the next page, select the users you want to provide the new tab view to, and click Next.


7) On the final page, select the applications that you want to add the alternative tab to (probably where the standard tab exists currently). Click Save to finish.



8) The new tab should now be visible in the apps you have selected. However, you may have noticed that the standard tab is still visible in your applications. As you can see below, I still have the Accounts standard tab, and the Accounts alternative tab visible, both called "Accounts".



The standard tabs need to be removed for clarity. To do this, navigate to the Apps setup page (Setup -> App Setup -> Create -> Apps). Click the edit link next to one of the apps that contains both of the tabs.



9) On the edit screen, Under the tab selection panel, move the old standard tab from the right hand side column to the left. Move the new alternative tab (at the end of the list) up the tab order to replace the old standard tab. Click Save to confirm your changes.





10) Finally, Click on your new tab to view your new object home page!


The new object home page is largely the same as the view page found by clicking the "Go" button on the original screen. You can use this interface to easily navigate through large amounts of objects. The current view of the data can be simply altered using the combo box in the top left hand corner of the page. You can order the view by different fields, and use the A-Z links in the top right hand corner to skip to specific alphabetic subsets of your data.


At the bottom of the page, you will find a link back to the old home page. This is useful in case you actually decide once in a while that you want to see your recent items or follow one of the default links for a standard object.

So there you have it, a much improved standard landing page for all of your objects. This is still far from ideal I admit, but I believe it is a definite step in the right direction. Most importantly I feel using this kind of view is intuitive. There is no longer all the confusion of recent views, especially debilitating for new users.

If you have any problems, questions or improvement suggestions, please add a comment below... Happy tabbing!


NOTE: If you want to remove the standard tab from being accessed entirely by a set of users, simply navigate the user profile settings (Setup -> Administration Setup -> Manage Users -> Profiles). Click the edit link next to a profiles you want to alter. Find the section where standard tab access is defined, and in the combo box next to the standard object tab, select the "tab hidden" option. Any user with this profile will now not be able to view the old standard tab, only the new alternative tab.

Standard Profile User Interface:



Enhanced Profile User Interface:



Tuesday, 22 March 2011

Working with Apex data tables: Confirming choices

In my previous post, I used Apex page messages to provide direct feedback from an action to users. If the action you are about to perform is particularly critical or hard to reverse, you may want to add some kind of confirmation mechanism. Of course we could simply use a javascript function on the page to produce a simple confirm pop up, but it is usually preferable to provide something more comprehensive. An effective way to do this in Salesforce is to create a two page Visualforce menu consisting of an action page and a confirmation page, where we can make sure the user is aware of the action they are about to perform.

I have built an example of such a menu based on the page and controller from my previous post. When the user selects contact records and clicks on "process selected contacts", they are taken to a confirmation page that displays the contacts that they have selected, and asks them to confirm that these are the records they wish to process. This confirmation page shares the same controller as the main selection page. They can choose to cancel, which will return them to the previous selection menu taking no action, or click confirm to accept the selections and then be returned to the selection menu. Here is a screenshot of the confirmation screen:



In terms of altering the controller code, I added two new actions to confirm and cancel processing the contact records. Users can be directed to a particular page by returning a page reference (of the form "Page.*Visualforce page name*") in the action, or null to remain on the same page. If no records are selected on the first page, then instead of being directed to the confirmation page, the user will remain on the selection page, and an error message will be displayed.

In order for menus like this to work, the two pages must share the same controller type. Also, ensure that all page references used to change the page do not have the redirect attribute set to true, otherwise the users selections will be lost as the controller is reset.

Below is the Apex controller and Visualforce page code for the example.

Controller:
public class WorkingWithApexDataTablesController {

 public List<ContactWrapper> allContacts { get; set; }
 public Boolean allChecked { get; set; }
 
 public WorkingWithApexDataTablesController () {
  allContacts = new List<ContactWrapper>();
  allChecked = false;
  
  for(Contact contact: [select Name, Title, Department, Email                                   from Contact ]){ 
   allContacts.add(new ContactWrapper(contact));
  } 
 }
 
 public PageReference CheckAll(){
  
  for(ContactWrapper contact : allContacts){
   contact.selected = allChecked;
  }
  
  return null;
 }
 
 public PageReference ProcessSelectedContacts(){
  
  // If at least one contact has been selected,
  // forward to confrimation page
  for (ContactWrapper contactWrapper : allContacts ){
   if(contactWrapper.selected == true){
    return Page.WorkingWithApexDataTablesConfirmation;
   }
  }  
  
  // if no contacts have been selected, write an error message
  Apexpages.addMessage(new ApexPages.Message (ApexPages.Severity.ERROR,                                               'No contacts selected'));
  return null;
 }

 public PageReference confirmSelectedContacts(){
   
  List<String> selectedContacts = new List<String>{};   

  for (ContactWrapper contactWrapper : allContacts ){
   if(contactWrapper.selected == true){
    selectedContacts.add(contactWrapper.con.Name);
   }
  }
  
  // otherwise, write a confirmation message 
  Apexpages.addMessage(new ApexPages.Message (
     ApexPages.Severity.CONFIRM, selectedContacts.size() + 
     ' contacts selected ' + selectedContacts));
  
  // If all contacts have been selected, write a warning message
  if(selectedContacts.size() == allContacts.size()){
   Apexpages.addMessage(new ApexPages.Message (
     ApexPages.Severity.WARNING, 'All contacts selected'));
  }
   
  return Page.WorkingWithApexDataTables;
 }
 
 public PageReference cancelConfirmSelectedContacts(){
   
  // If the users cancels the action at the confirmation screen, 
  // return them to the main screen with a cancellation message
  Apexpages.addMessage(new ApexPages.Message (
    ApexPages.Severity.CONFIRM, 'Action Cancelled'));   
   
  return Page.WorkingWithApexDataTables;
 }
 
 public List<Contact> getSelectedContactObjects(){
  List<Contact> selectedContactObjects = new List<Contact>{};
  
  for (ContactWrapper contactWrapper : allContacts ){
   if(contactWrapper.selected == true){
    selectedContactObjects.add(contactWrapper.con);
   }
  }
  
  return selectedContactObjects;
 }

 public class ContactWrapper {
  
  public Contact con{get; set;}
  public Boolean selected {get; set;}
        
  public ContactWrapper(Contact c){
   con = c;
   selected = false;
  }
 }
}

WorkingWithApexDataTables Page:
<apex:page controller="WorkingWithApexDataTablesController">
  
  <apex:sectionHeader title="Working With Apex Data Tables"/>
  
  <apex:pageMessages />
  
  <apex:form >

    <apex:dataTable value="{!allContacts}" var="c" id="contactsTable">
      <apex:column >
        <apex:facet name="header">
          <apex:inputCheckbox value="{!allChecked}">
            <apex:actionSupport event="onclick" action="{!CheckAll}"
                                rerender="contactsTable"/>
          </apex:inputCheckbox>
        </apex:facet>
        <apex:inputCheckbox value="{!c.selected}"/>
      </apex:column>
      <apex:column value="{!c.con.Name}" headervalue="Full Name"/>
      <apex:column value="{!c.con.Title}" headervalue="Title"/>
      <apex:column value="{!c.con.Department}" 
                   headervalue="Department"/>
      <apex:column value="{!c.con.Email}" headervalue="Email"/>
    </apex:dataTable>

    <apex:commandButton action="{!ProcessSelectedContacts}" 
                        value="Process Selected Contacts"/>

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

WorkingWithApexDataTablesConfirmation Page:
<apex:page controller="WorkingWithApexDataTablesController">
  
  <apex:sectionHeader                                                           title="Working With Apex Data Tables (Confirmation)"/>
  
  <apex:form >

    <apex:outputText value="You have selected the following contacts for                            processing, are you sure?"/>

    <apex:dataTable value="{!selectedContactObjects}" var="con"                             id="selectedContactsTable">
      <apex:column value="{!con.Name}" headervalue="Full Name"/>
      <apex:column value="{!con.Title}" headervalue="Title"/>
      <apex:column value="{!con.Department}" headervalue="Department"/>
      <apex:column value="{!con.Email}" headervalue="Email"/>
    </apex:dataTable>

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

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

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

Thursday, 1 July 2010

Adding alphabetical lists in Salesforce PDFs

One of the better features of Salesforce and apex programming is the ability to generate Visualforce pages as PDFs by simply using the renderAs="pdf" attribute notation in the apex:page tag. However, recently when using this feature to generate a list of conditions, I noticed that whenever you define an apex datalist, or an ordered list in html that uses letters (a,b,c,d) as the markers for each element in the list, these are rendered in the PDF incorrectly.

Take the following example of a page and controller:

Page:
<apex:page showHeader="false" controller="LetterListController" standardStylesheets="false" sidebar="false">

<apex:dataList value="{!accounts}" type="a" var="account" id="theList" >
<apex:outputText value="{!account.name}"/>
</apex:dataList>

<ol type="a">
<li>First Item</li>
<li>Second Item</li>
<li>Third Item</li>
<li>Last Item</li>
</ol>

</apex:page>

Controller:
public class LetterListController {

List<Account> accounts;

public List<Account> getAccounts() {
if(accounts == null) accounts = [select name from account limit 10];
return accounts;
}
}


When the Letter List page is rendered in Salesforce, the following output appears-


Absolutely fine, but when we add the renderAs="pdf" attribute in the page tag definition, the PDF output is -


The apex datalist has been rendered as a list with blobs, while the html list has been changed to be ordered by numbers. This is quite frustrating, but the solution is simple. You can choose the bullet point class of a list using the css attribute list-style-type. So all we need to do is create a style class on the page inside head tags, and then apply this class to the two lists.

Page:

<apex:page showHeader="false" controller="LetterListController" standardStylesheets="false" sidebar="false" renderas="PDF">

<head>
<style>
.letterList{
list-style-type: lower-alpha;
}
</style>
</head>


<apex:dataList value="{!accounts}" var="account" id="theList" styleClass="letterList">
<apex:outputText value="{!account.name}"/>
</apex:dataList>

<ol class="letterList" type="a">
<li>First Item</li>
<li>Second Item</li>
<li>Third Item</li>
<li>Last Item</li>
</ol>

</apex:page>

The output PDF is now -