• andresperez
  • NEWBIE
  • 50 Points
  • Member since 2008

  • Chatter
    Feed
  • 1
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 4
    Questions
  • 61
    Replies

I have a jsp page which is opening a apex page in a new window.  when some one clicks save on the apex page, the requirement is to save the changed data , close apex page window and refresh the calling parent.

 

Any help is highly appreciated.

 

P.S. I have tried window.top.close() which closes down the window without saving the data.

 

Thanx

 

S

  • January 26, 2009
  • Like
  • 0

Dear salesforce.com users,

 

I want to share with you one Appex class that sorts a List<sObject> by any field in ascending or descending order. The List<sObject> is generated by any SOQL statement, so it can be made of custom and/or standard objects. 

 

Using this class is quite simple, and because I have written unit tests that validates 100% of the code you can easily use it in production sytems.

 

The class performs quite well because the sorting is done in memory (using Maps, Sets and Lists). It also detects if the sort has been done for this field so it does not need to resort (even if it is in reverse order).

 

Before going into details of the Appex class, let me show you how the class is used...

 

The VisualForce page:

Nothing fancy here... Just a page building a datatable with three columns and command buttons on the table headers to sort the data.

<apex:page controller="aaSorterContact">
<apex:form >
<apex:pageBlock >
<apex:pageBlockSection columns="1" ID="AjaxTable">
<apex:datatable value="{!List}" var="acc" Border="1" cellspacing="1" cellpadding="5">
<apex:column >
<apex:facet name="header">
<apex:commandButton action="{!SortByName}"

value="Sort By Name" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Name}" />
</apex:column>
<apex:column >
<apex:facet name="header">
<apex:commandButton action="{!SortByPhone}"

value="Sort By Phone" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Phone}" />

</apex:column>
<apex:column >
<apex:facet name="header">

<apex:commandButton action="{!SortByAccount}"

value="Sort By Account" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Account.Name}" />

</apex:column>
</apex:datatable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>

The controller:

Couple things going in here, but that is just to make the page look nice... Nothing really to do with the sorting.

public class aaSorterContact {
private String sortedBy = null;
private Boolean sortAscending = null;
private AP_SortHelper sorter = new AP_SortHelper();
private List<Contact> sortedList = null;

public aaSorterContact() {
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact];
}
public PageReference SortByName() {
setSortedBy('NAME');
sortedList = (List<Contact>) sorter.getSortedList('Name', sortAscending);
return null;
}
public PageReference SortByAccount() {
setSortedBy('ACCOUNT');
sortedList = (List<Contact>) sorter.getSortedList('Account.Name', sortAscending);
return null;
}
public PageReference SortByPhone() {
setSortedBy('PHONE');
sortedList = (List<Contact>) sorter.getSortedList('Phone', sortAscending);
return null;
}
public List<Contact> getList() {
if (sortedList == null) {
SortByName();
}
return sortedList;
}
private void setSortedBy(String value) {
if (sortedBy == value) {
sortAscending = !sortAscending;
} else {
sortAscending = true;
}
sortedBy = value;
}
}

 

Let me talk about the easy part first...

 

There are methods that answer the calls from the commandbuttons on the page:

 

  • SortByName
  • SortByAccount
  • SortByPhone

 

These methods follow the same structure:

setSortedBy('NAME');
sortedList = (List<Contact>) sorter.getSortedList('Name', sortAscending);
return null;

First, it calls a method setSortedBy() to find out the ascending or descending order. If the user clicks on a different button, the table is sorted ascending by that column, ortherwise the order is inverted from Ascending to descending and viceversa.

 

Second, it calls the method in the Appex class that does the sorting. (I will explain on detail how to use the Appex class, keep reading) :smileywink:

 

Finally, the controller's method returns a null value to the page.

 

The controller's constructor gets the list from the database.

public aaSorterContact() {
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact];
}

Since the buttons use the rerendered propery (using AJAX), the class constructor is only called at the initial page load rather than every time the buttons are clicked, therefore the SOQL gets called only once regardless of how many times the data table gets sorted.

 

Finally, the more interesting part...

 

The Appex class that sorts:

You don't really need to understand how this class works to use it, but those of you who are interested...

public class AP_SortHelper {     // <ID, Position>
private Map<String, Integer> listPosition = null; // <FieldName, <FieldValues>>
private Map<String, List<String>> sortedFieldValuesPerFieldName = null; // <FieldName, <FieldValue, <IDs>>>
private Map<String, Map<String, List<String>>> sObjectIDsPerFieldNames = null;

// Properties
public List<sObject> originalList {get; set;}

// Constructor
public AP_SortHelper() {
originalList = null;
}// Public Method
public List<sObject> getSortedList(String fieldName, Boolean ascending) {
if (originalList == null) {
// Assume that originalList has a not NULL value.
// If the class who uses this method has not assigned a value it will get an Exception which
// needs to be handled by the calling class. // Force the exception...
originalList.clear();
} // Make field name uppercase
fieldName = fieldName.toUpperCase(); // Get sorted list
return makeSortedList(fieldName, ascending);
}
public List<sObject> getSortedList(List<sObject> originalList, String fieldName, Boolean ascending) {
this.originalList = originalList;
sortedFieldValuesPerFieldName = null;
return getSortedList(fieldName, ascending);
}

// Private Methods
private void InitializeFieldName(String fieldName) {
String sObjectID;
Integer position;
String fieldValue;
List<String> sObjectIDs = null;
Set<String> valuesForFieldSet = null; // Sets automatically omit duplicate values
List<String> valuesForFieldList = null;
Map<String, List<String>> sObjectIDsPerFieldValues = null;

// Make sortedFieldValuesPerFieldName
if (sortedFieldValuesPerFieldName == null) {
listPosition = new Map<String, Integer>();
sortedFieldValuesPerFieldName = new Map<String, List<String>>();
sObjectIDsPerFieldNames = new Map<String, Map<String, List<String>>>();
}

// Get (or create) map of sObjectIDsPerFieldValues
sObjectIDsPerFieldValues = sObjectIDsPerFieldNames.get(fieldName);
if (sObjectIDsPerFieldValues == null) {
sObjectIDsPerFieldValues = new Map<String, List<String>>();
sObjectIDsPerFieldNames.put(fieldName, sObjectIDsPerFieldValues);
}
if (!sortedFieldValuesPerFieldName.keySet().contains(fieldName)) {
// Objects need to be initialized
position = 0;
valuesForFieldSet = new Set<String>();
listPosition = new Map<String, Integer>();

for (sObject sObj : originalList) {
sObjectID = sObj.ID;
fieldValue = getValue(sObj, fieldName);

// Add position to list
listPosition.put(sObjectID, position++);

// Add the value to the set (sets rather than lists to prevent duplicates)
valuesForFieldSet.add(fieldValue);

// Get (or create) map of sObjectIDs
sObjectIDs = sObjectIDsPerFieldValues.get(fieldValue);
if (sObjectIDs == null) {
sObjectIDs = new List<String>();
sObjectIDsPerFieldValues.put(fieldValue, sObjectIDs);
}

// Add ID to sObjectIDs
sObjectIDs.add(sObjectID);
}

// Sort set items (Need to convert to list)
valuesForFieldList = new List<String>();
valuesForFieldList.addAll(valuesForFieldSet);
valuesForFieldList.sort();

// Now add it to the map.
sortedFieldValuesPerFieldName.put(fieldName, valuesForFieldList);
}
}
private List<sObject> makeSortedList(String fieldName, Boolean ascending) {
Integer position;
List<String> sObjectIDs = null;
List<String> valuesForFieldList = null; // Initialize objects
InitializeFieldName(fieldName); // Get a list of the same type as the "originalList"
List<sObject> outputList = originalList.clone();
outputList.clear(); // Get a list of sorted values
valuesForFieldList = sortedFieldValuesPerFieldName.get(fieldName);

// for each sorted value
for (String fieldValue : valuesForFieldList) {
// Get lisft of IDs
sObjectIDs = sObjectIDsPerFieldNames.get(fieldName).get(fieldValue);

// for each ID
for (String ID : sObjectIDs) {
// Get position in originalList
position = listPosition.get(ID); // Add each sObject to the list.
if ((ascending) || (outputList.size()==0)) {
outputList.add(originalList[position]);
} else {
outputList.add(0, originalList[position]);
}
}
}
return outputList;
}
private static String getValue(sObject sObj, String fieldName) {
// This returns the sObject desired in case the fieldName refers to a linked object.
Integer pieceCount;
String[] fieldNamePieces;

fieldNamePieces = fieldName.split('\\.');
pieceCount = fieldNamePieces.size();
for (Integer i = 0; i < (pieceCount-1); i++) {
sObj = sObj.getSObject(fieldNamePieces[i]);
}
return String.valueOf(sObj.get(fieldNamePieces[pieceCount-1]));
}

// Unit testing
/*
static testMethod void testSortCustomObject() {
List<TPValue__c> TPValues;
AP_SortHelper sorter = new AP_SortHelper();
String fieldName;

TPValues = [SELECT TPName__r.TPName__c, Value__c FROM TPValue__c LIMIT 50];
fieldName = 'Value__c';
testOrderedList(sorter.getSortedList(TPValues, fieldName, true), fieldName, true);

fieldName = 'TPName__r.TPName__c';
testOrderedList(sorter.getSortedList(TPValues, fieldName, true), fieldName, true);
}
*/
static testMethod void testSimpleField_Ascending() {
testSortingContacts('Name', true);
}
static testMethod void testSimpleField_Descending() {
testSortingContacts('Name', False);
}
static testMethod void testLookupField_Ascending() {
testSortingContacts('Account.Name', True);
}
static testMethod void testLookupField_Decending() {
testSortingContacts('Account.Name', False);
}
static testMethod void testMultipleCalls() {
AP_SortHelper sorter;
sorter = testSortingContacts(null, 'Name', true);
testSortingContacts(sorter, 'Name', False);
testSortingContacts(sorter, 'Account.Name', True);
testSortingContacts(sorter, 'Account.Name', False);
}
static testMethod void testForgotOriginalList() {
Boolean exceptionDetected = false;
AP_SortHelper sorter = new AP_SortHelper();
try {
sorter.getSortedList('Name', true);
} catch (NullPointerException e) {
exceptionDetected = true;
}
System.assert(exceptionDetected);
}
static testMethod void testPassingList() {
AP_SortHelper sorter = new AP_SortHelper();
List<Contact> contacts = [SELECT Name, Phone, Account.Name FROM Contact LIMIT 50];
List<Contact> sortedList = (List<Contact>) sorter.getSortedList(contacts, 'Name', true);
testOrderedList(sortedList, 'Name', true);
}
private static void testSortingContacts(string fieldName, Boolean isAscending) {
testSortingContacts(null, fieldName, isAscending);
}
private static AP_SortHelper testSortingContacts(AP_SortHelper sorter, string fieldName, Boolean isAscending) {
// If sorted is null,create it.
if (sorter == null) {
sorter = new AP_SortHelper();
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact LIMIT 50];
}

// Sort list
List<Contact> sortedList = (List<Contact>) sorter.getSortedList(fieldName, isAscending); // Test sort order
testOrderedList(sortedList, fieldName, isAscending);

return sorter;
}
private static void testOrderedList(List<sObject> sortedList, string fieldName, Boolean isAscending) {
String lastValue = null;
String currentValue = null; for (sObject sObj : sortedList) {
currentValue = getValue(sObj, fieldName);
if ((lastValue != null) && (currentValue != null)) { String strDebug = '';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\nSTART';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\n[Ascending:'+isAscending+']';
strDebug += '\n[Previous:'+lastValue+'] [IsNull():'+(lastValue==null)+']';
strDebug += '\n[Current:'+currentValue+'] [IsNull():'+(currentValue==null)+']';
strDebug += '\n[CompareTo:'+(currentValue.compareTo(lastValue))+']';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\nEND';
strDebug += '\n--------------------------------------------------------------';
System.debug(strDebug); if (isAscending) {
System.assertEquals(currentValue.compareTo(lastValue)>=0, true);
} else {
System.assertEquals(currentValue.compareTo(lastValue)<=0, true);
}
}
lastValue = currentValue;
}
}
}

 

How to use this class?

  1. Create an instance of this class AP_SortHelper()
  2. Assign the list to sort. Get this list using SOQL.
  3. Call the getSortedList() method which takes two fields:
    1. The name of the field as it was used in the SOQL
    2. The order (true for ascending, false for descending

 


For now, I have one question to the group...

 

This message is getting long... Is there a better place to post it? The way I see it, AppeXchange is applications not for independent utility classes.

Message Edited by andresperez on 01-28-2009 10:45 AM
Hi,
 
I need to have an sObject where the name field is unique for each user. A user can  not have two or more records with the same "name", but it is possible for different  users to have records with the same name. Let me explain....
 
Let's suppose I have an sObject with this data:
 
Owner   Name
user1  name1
user1  name2
 
If "user1" tries to add a row named "name1", the system should prevent him from doing so because "user1" already has a row with "name1". On the other hand if "user2" tries to add a row named "name1" the system should allow this, because "user2" does not have a row named "name1".
 
So far, I have come to this solution... But I would like to know if there is a better any of doing it.
 
Code:
trigger PreventDuplicateNameForUser on TPName__c (before insert, before update) {
    for (TPName__c TPName : Trigger.new) {
        List<TPName__c> listFound = [SELECT name
FROM TPName__c
WHERE ownerid = :UserInfo.getUserID()
AND name = :TPName.name];         if (listFound.size() > 0) {
            Trigger.new[0].addError('You already defined a Parameter Name called ['
+ TPName.name +']. Please use another name and try again');
        }
} }

 One of the things that concern me is that triggers are not always fired.
 
Is there a better way of doing this... I mean is there something to configure in a sObject to make it behave like this?
 
Thanks
 
 
Hi,
 
I am having a problem with inheritance. I am not sure what I am doing wrong... please help.
 
I have an abstract class that looks like this:
public abstract class TokenHandlerAbstract {
  protected Pattern p = null;
 
public Boolean isValid(String testString, TPParams params) {
    Pattern p = getPattern();
    return isPatternMatch(p, testString);
  }
  protected virtual Pattern getPattern() {
    String regexp = functionName + '(.*)';
    if ((p == null) || (p.pattern() != regexp)) {
      p = Pattern.compile(regexp);
    }
    return p;
  }
}
 
This class is extended with a class that looks like this:
public class TokenHandlerString extends TokenHandlerAbstract {
  protected override Pattern getPattern() {
    // Anything surrounded by single quotes
    String regexp = '\'.*\'';
    if ((p == null) || (p.pattern() != regexp)) {
      p = Pattern.compile(regexp);
    }
    return p; 
  }
}

These classes get called from a third class that looks like this:

public class TokenValueFinder {
  private TokenHandlerString thString = new TokenHandlerString();
  public String findValue(String testString, TPParams params) {
    if (thString.isValid(testString, params)) {
      ...
    }
  }
}

When I view the page I get this error:

System.TypeException: Method is not visible: [TokenHandlerString].getPattern()

Class.TokenHandlerAbstract.isValid: line 7, column 21
Class.TokenValueFinder.findValue: line 31, column 20
Class.TPTextParser2.privateParse: line 35, column 31
Class.TPTextParser2.Parse: line 15, column 9
Class.TPResolved2.getTemplateResolved: line 198, column 28
External entry point

If I change the visibility of getPattern() from protected to public, the error goes away. But why?
 
I understand that isValid()has to be public because I am calling the method from a different class. But getPattern() is being called from the same class or one that inherits from it.
 
Thanks
 
Andres Perez
I am trying to build a site that allows users to log on and see only their data in the custom objects.
 
The documentation I have found (Force.com Developer Guide, Chapter 14) suggests that I clone the "Customer Portal User" profile. But I do not see that profile in the Setup > Manage Users > Profile. The closest profile I have is "Customer Portal Manager".
 
The only profile I can set up in de "Customer Portal" is "Customer Portal Manager" (I would prefer to use "user" rather than "manager", for security purposes), but the "manager" profile does not show any custom objects.
 
What am I doing wrong? Did I delete anything that I was not supposed to?
 
Thanks
 
Andres Perez

Hi,

 

I have a VF page in which i have Apex input text controls and a command Button control.

I am able to fill the Text boxes using the properties created in the controller.

 

My requirement here is when clicked on the command button in the Vf page i want to dynamically add a input text to the VF page.

 

Can we do it using Apex code??.

 

I have been looking around for adding controls in VF page using Apex code. I went through the developers guide and cook book for reference even then i failed to get the result.

 

Do any one have an idea about adding apex controls dynamically??

Please help me out...This might be a very silly question to ask but i am not able to resolve this problem from days.

 

Thanks in Advance,

pspl 

 

 

 

 

 

I have a jsp page which is opening a apex page in a new window.  when some one clicks save on the apex page, the requirement is to save the changed data , close apex page window and refresh the calling parent.

 

Any help is highly appreciated.

 

P.S. I have tried window.top.close() which closes down the window without saving the data.

 

Thanx

 

S

  • January 26, 2009
  • Like
  • 0

Dear salesforce.com users,

 

I want to share with you one Appex class that sorts a List<sObject> by any field in ascending or descending order. The List<sObject> is generated by any SOQL statement, so it can be made of custom and/or standard objects. 

 

Using this class is quite simple, and because I have written unit tests that validates 100% of the code you can easily use it in production sytems.

 

The class performs quite well because the sorting is done in memory (using Maps, Sets and Lists). It also detects if the sort has been done for this field so it does not need to resort (even if it is in reverse order).

 

Before going into details of the Appex class, let me show you how the class is used...

 

The VisualForce page:

Nothing fancy here... Just a page building a datatable with three columns and command buttons on the table headers to sort the data.

<apex:page controller="aaSorterContact">
<apex:form >
<apex:pageBlock >
<apex:pageBlockSection columns="1" ID="AjaxTable">
<apex:datatable value="{!List}" var="acc" Border="1" cellspacing="1" cellpadding="5">
<apex:column >
<apex:facet name="header">
<apex:commandButton action="{!SortByName}"

value="Sort By Name" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Name}" />
</apex:column>
<apex:column >
<apex:facet name="header">
<apex:commandButton action="{!SortByPhone}"

value="Sort By Phone" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Phone}" />

</apex:column>
<apex:column >
<apex:facet name="header">

<apex:commandButton action="{!SortByAccount}"

value="Sort By Account" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Account.Name}" />

</apex:column>
</apex:datatable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>

The controller:

Couple things going in here, but that is just to make the page look nice... Nothing really to do with the sorting.

public class aaSorterContact {
private String sortedBy = null;
private Boolean sortAscending = null;
private AP_SortHelper sorter = new AP_SortHelper();
private List<Contact> sortedList = null;

public aaSorterContact() {
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact];
}
public PageReference SortByName() {
setSortedBy('NAME');
sortedList = (List<Contact>) sorter.getSortedList('Name', sortAscending);
return null;
}
public PageReference SortByAccount() {
setSortedBy('ACCOUNT');
sortedList = (List<Contact>) sorter.getSortedList('Account.Name', sortAscending);
return null;
}
public PageReference SortByPhone() {
setSortedBy('PHONE');
sortedList = (List<Contact>) sorter.getSortedList('Phone', sortAscending);
return null;
}
public List<Contact> getList() {
if (sortedList == null) {
SortByName();
}
return sortedList;
}
private void setSortedBy(String value) {
if (sortedBy == value) {
sortAscending = !sortAscending;
} else {
sortAscending = true;
}
sortedBy = value;
}
}

 

Let me talk about the easy part first...

 

There are methods that answer the calls from the commandbuttons on the page:

 

  • SortByName
  • SortByAccount
  • SortByPhone

 

These methods follow the same structure:

setSortedBy('NAME');
sortedList = (List<Contact>) sorter.getSortedList('Name', sortAscending);
return null;

First, it calls a method setSortedBy() to find out the ascending or descending order. If the user clicks on a different button, the table is sorted ascending by that column, ortherwise the order is inverted from Ascending to descending and viceversa.

 

Second, it calls the method in the Appex class that does the sorting. (I will explain on detail how to use the Appex class, keep reading) :smileywink:

 

Finally, the controller's method returns a null value to the page.

 

The controller's constructor gets the list from the database.

public aaSorterContact() {
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact];
}

Since the buttons use the rerendered propery (using AJAX), the class constructor is only called at the initial page load rather than every time the buttons are clicked, therefore the SOQL gets called only once regardless of how many times the data table gets sorted.

 

Finally, the more interesting part...

 

The Appex class that sorts:

You don't really need to understand how this class works to use it, but those of you who are interested...

public class AP_SortHelper {     // <ID, Position>
private Map<String, Integer> listPosition = null; // <FieldName, <FieldValues>>
private Map<String, List<String>> sortedFieldValuesPerFieldName = null; // <FieldName, <FieldValue, <IDs>>>
private Map<String, Map<String, List<String>>> sObjectIDsPerFieldNames = null;

// Properties
public List<sObject> originalList {get; set;}

// Constructor
public AP_SortHelper() {
originalList = null;
}// Public Method
public List<sObject> getSortedList(String fieldName, Boolean ascending) {
if (originalList == null) {
// Assume that originalList has a not NULL value.
// If the class who uses this method has not assigned a value it will get an Exception which
// needs to be handled by the calling class. // Force the exception...
originalList.clear();
} // Make field name uppercase
fieldName = fieldName.toUpperCase(); // Get sorted list
return makeSortedList(fieldName, ascending);
}
public List<sObject> getSortedList(List<sObject> originalList, String fieldName, Boolean ascending) {
this.originalList = originalList;
sortedFieldValuesPerFieldName = null;
return getSortedList(fieldName, ascending);
}

// Private Methods
private void InitializeFieldName(String fieldName) {
String sObjectID;
Integer position;
String fieldValue;
List<String> sObjectIDs = null;
Set<String> valuesForFieldSet = null; // Sets automatically omit duplicate values
List<String> valuesForFieldList = null;
Map<String, List<String>> sObjectIDsPerFieldValues = null;

// Make sortedFieldValuesPerFieldName
if (sortedFieldValuesPerFieldName == null) {
listPosition = new Map<String, Integer>();
sortedFieldValuesPerFieldName = new Map<String, List<String>>();
sObjectIDsPerFieldNames = new Map<String, Map<String, List<String>>>();
}

// Get (or create) map of sObjectIDsPerFieldValues
sObjectIDsPerFieldValues = sObjectIDsPerFieldNames.get(fieldName);
if (sObjectIDsPerFieldValues == null) {
sObjectIDsPerFieldValues = new Map<String, List<String>>();
sObjectIDsPerFieldNames.put(fieldName, sObjectIDsPerFieldValues);
}
if (!sortedFieldValuesPerFieldName.keySet().contains(fieldName)) {
// Objects need to be initialized
position = 0;
valuesForFieldSet = new Set<String>();
listPosition = new Map<String, Integer>();

for (sObject sObj : originalList) {
sObjectID = sObj.ID;
fieldValue = getValue(sObj, fieldName);

// Add position to list
listPosition.put(sObjectID, position++);

// Add the value to the set (sets rather than lists to prevent duplicates)
valuesForFieldSet.add(fieldValue);

// Get (or create) map of sObjectIDs
sObjectIDs = sObjectIDsPerFieldValues.get(fieldValue);
if (sObjectIDs == null) {
sObjectIDs = new List<String>();
sObjectIDsPerFieldValues.put(fieldValue, sObjectIDs);
}

// Add ID to sObjectIDs
sObjectIDs.add(sObjectID);
}

// Sort set items (Need to convert to list)
valuesForFieldList = new List<String>();
valuesForFieldList.addAll(valuesForFieldSet);
valuesForFieldList.sort();

// Now add it to the map.
sortedFieldValuesPerFieldName.put(fieldName, valuesForFieldList);
}
}
private List<sObject> makeSortedList(String fieldName, Boolean ascending) {
Integer position;
List<String> sObjectIDs = null;
List<String> valuesForFieldList = null; // Initialize objects
InitializeFieldName(fieldName); // Get a list of the same type as the "originalList"
List<sObject> outputList = originalList.clone();
outputList.clear(); // Get a list of sorted values
valuesForFieldList = sortedFieldValuesPerFieldName.get(fieldName);

// for each sorted value
for (String fieldValue : valuesForFieldList) {
// Get lisft of IDs
sObjectIDs = sObjectIDsPerFieldNames.get(fieldName).get(fieldValue);

// for each ID
for (String ID : sObjectIDs) {
// Get position in originalList
position = listPosition.get(ID); // Add each sObject to the list.
if ((ascending) || (outputList.size()==0)) {
outputList.add(originalList[position]);
} else {
outputList.add(0, originalList[position]);
}
}
}
return outputList;
}
private static String getValue(sObject sObj, String fieldName) {
// This returns the sObject desired in case the fieldName refers to a linked object.
Integer pieceCount;
String[] fieldNamePieces;

fieldNamePieces = fieldName.split('\\.');
pieceCount = fieldNamePieces.size();
for (Integer i = 0; i < (pieceCount-1); i++) {
sObj = sObj.getSObject(fieldNamePieces[i]);
}
return String.valueOf(sObj.get(fieldNamePieces[pieceCount-1]));
}

// Unit testing
/*
static testMethod void testSortCustomObject() {
List<TPValue__c> TPValues;
AP_SortHelper sorter = new AP_SortHelper();
String fieldName;

TPValues = [SELECT TPName__r.TPName__c, Value__c FROM TPValue__c LIMIT 50];
fieldName = 'Value__c';
testOrderedList(sorter.getSortedList(TPValues, fieldName, true), fieldName, true);

fieldName = 'TPName__r.TPName__c';
testOrderedList(sorter.getSortedList(TPValues, fieldName, true), fieldName, true);
}
*/
static testMethod void testSimpleField_Ascending() {
testSortingContacts('Name', true);
}
static testMethod void testSimpleField_Descending() {
testSortingContacts('Name', False);
}
static testMethod void testLookupField_Ascending() {
testSortingContacts('Account.Name', True);
}
static testMethod void testLookupField_Decending() {
testSortingContacts('Account.Name', False);
}
static testMethod void testMultipleCalls() {
AP_SortHelper sorter;
sorter = testSortingContacts(null, 'Name', true);
testSortingContacts(sorter, 'Name', False);
testSortingContacts(sorter, 'Account.Name', True);
testSortingContacts(sorter, 'Account.Name', False);
}
static testMethod void testForgotOriginalList() {
Boolean exceptionDetected = false;
AP_SortHelper sorter = new AP_SortHelper();
try {
sorter.getSortedList('Name', true);
} catch (NullPointerException e) {
exceptionDetected = true;
}
System.assert(exceptionDetected);
}
static testMethod void testPassingList() {
AP_SortHelper sorter = new AP_SortHelper();
List<Contact> contacts = [SELECT Name, Phone, Account.Name FROM Contact LIMIT 50];
List<Contact> sortedList = (List<Contact>) sorter.getSortedList(contacts, 'Name', true);
testOrderedList(sortedList, 'Name', true);
}
private static void testSortingContacts(string fieldName, Boolean isAscending) {
testSortingContacts(null, fieldName, isAscending);
}
private static AP_SortHelper testSortingContacts(AP_SortHelper sorter, string fieldName, Boolean isAscending) {
// If sorted is null,create it.
if (sorter == null) {
sorter = new AP_SortHelper();
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact LIMIT 50];
}

// Sort list
List<Contact> sortedList = (List<Contact>) sorter.getSortedList(fieldName, isAscending); // Test sort order
testOrderedList(sortedList, fieldName, isAscending);

return sorter;
}
private static void testOrderedList(List<sObject> sortedList, string fieldName, Boolean isAscending) {
String lastValue = null;
String currentValue = null; for (sObject sObj : sortedList) {
currentValue = getValue(sObj, fieldName);
if ((lastValue != null) && (currentValue != null)) { String strDebug = '';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\nSTART';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\n[Ascending:'+isAscending+']';
strDebug += '\n[Previous:'+lastValue+'] [IsNull():'+(lastValue==null)+']';
strDebug += '\n[Current:'+currentValue+'] [IsNull():'+(currentValue==null)+']';
strDebug += '\n[CompareTo:'+(currentValue.compareTo(lastValue))+']';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\nEND';
strDebug += '\n--------------------------------------------------------------';
System.debug(strDebug); if (isAscending) {
System.assertEquals(currentValue.compareTo(lastValue)>=0, true);
} else {
System.assertEquals(currentValue.compareTo(lastValue)<=0, true);
}
}
lastValue = currentValue;
}
}
}

 

How to use this class?

  1. Create an instance of this class AP_SortHelper()
  2. Assign the list to sort. Get this list using SOQL.
  3. Call the getSortedList() method which takes two fields:
    1. The name of the field as it was used in the SOQL
    2. The order (true for ascending, false for descending

 


For now, I have one question to the group...

 

This message is getting long... Is there a better place to post it? The way I see it, AppeXchange is applications not for independent utility classes.

Message Edited by andresperez on 01-28-2009 10:45 AM

We're using Conga Merge and an Excel DCount function which is supposed to count non blank values in a column. We have a SF text field that has a Case condition which returns Null if false.  However, when we run a SF report with this field and view it in Excel, while the field is (blank) Excel does not see it as null.  If I "delete" the (blank) value in the field, then Excel sees it as null.

 

Yes, I'd rather use a csv file, but for Conga Merge reports, an Excel template is only option in this case.  I'm trying to see if there is some field value I should be using so the SF report sees this value as null.  (I see "-" in the SF report in these instances which must be the problem.)

 

Thanks!

I have created a VF page, which is included in the page layout of an object, that displays amounts from related records. Amount above 10.000.000 are displayed in the 6.0E+7 notation on screen. How can I prevent this?

 

The code that sets the field value:

this.noc1 = afcst.Forecasted_Amount__c;

 

Where Forecasted_Amount__c is a normal currency field in SF. noc1 is a Double in the code, however I tried with Decimal as well.

 

The pagecode that displays this field:

<td><apex:outputText id="noc1" value="{!noc1}" /></td>

 

 

Another question I have, is how to prevent the numbers to show with 1 decimal position. 1.000.000 will always be displayed as 1000000.0, regardless of what method I append to the first line of code (round(), toPlainString() etc..)


I have a list on whose columns I have applied sorting.The functionality works perfectly well.The problem arises when I try to sort on the columns regularly sometimes they loose values and sometimes they work well without any problems.

I had logged a case in Salesforce but,the reply was:->
"
Currently Salesforce does not support the VisualForce. For assistance with this you would need to go to www.Salesforce.com/Developers for assistance with this issue.
"
Please advise.


Message Edited by iceberg4u on 01-20-2009 10:29 PM
Hello,

I'm migrating a database for a Canadian group and they have a handy trigger (Access/VBA DLookup) in their Access database that finds a contact's province after insert, based on that person postal code. Postal codes in Canada are alphanumeric and the DLookup function enables a lookup within a range of alphanumeric values. For example, the postal code 'V3H 3A6' falls within the range 'V3H 2B7' and 'V3H 5S6', which represents all of the postal codes in a particular province. I have a table of values that defines the range but not each available postal code.

Is there any way to parse these alphanumeric ranges with Apex? In other words, can I find out if an alphanumeric string falls within a range of two alphanumeric strings. Can I use this existing table that defines only the ranges or do I need to build out my own new table? Or, is there a way to build in this logic into Apex to find an alphanumeric value in a range of two alphanumeric values?
Hi Guys,
 
I am new to salesforce. Can someone please make recomendation regarding Good Books, Tutorials etc reg. development and customization?
 
Thanks
 
M

I have a VF page for a standard object that uses standard controller and a controller extension. When an invalid object Id is passed, or record is unavailable (deleted or due to permissions), the standard controller throws the "hard-error" and the error is displayed in the standard SFDC UI (with the sidebar and header). My application has a completely cusom UI and I do not want to be "thrown" into the standard SFDC UI in case of an error. I tried to trap the error in the extension controller class, but it looks like standard controller traps it first and does not allow me to put in place any custom error handling.

Any suggestions?

  • November 20, 2008
  • Like
  • 0
I'd like to re-open the discussion of SortOrder on the OpportunityLineItem object. A thread from 3.5 years ago can be located here:
http://community.salesforce.com/sforce/board/message?board.id=general_development&message.id=3154

Looks like people from SF were going to look into it but obviously nothing has come to fruition. The reason I have put this in the Visualforce board is that we have have a few VF applications that could really take advantage of access to this field. Visualforce has also opened up new possibilities to UI design where the ability to manage SortOrder could be useful.

Also, no offense to salesforce.com, but the tool for sorting OpportunityLineItems is not that useful when there are multiple products with the same name. I have actually built a pretty slick sorting application but this is currently useless.

A lot of the concerns were about error handling. What happens if you have 3 line items but sort order is defined as, 1, 2, 2. Or 1, 2, 4. How about just throwing a sortOrder exception and force the developers to write good code?

Ideas? Thoughts?
http://ideas.salesforce.com/article/show/10092062/OpportunityLineItem_SortOrder_to_be_CreatableUpdatable

-Jason


Message Edited by TehNrd on 09-05-2008 01:22 PM
  • September 03, 2008
  • Like
  • 1