2

I want to allow my team to display some leads and tasks (and any known object) with custom conditions and display all the data on only one screen. I made some custom objects "blocks" containing SOQL elements :

  • base query ; ex: select * from lead where createdDate = TODAY
  • headers ; ex: Name, CreatedDate, id

I have a controller that get all those blocks then get all the records in wrappers with a list of headers and a list of those sobjects.

Then I have a visualforce page that use repeat vf command :

  • repeat on all wrappers to create tables
  • repeat on all headers to create the table header then fill the rows & 1st column is a link to the record

This way my team can work on only one screen with data we want.

But I would like to be able to format the output value, depending on the type. Obviously for dates and datetimes.

I am just thinking about one thing : I could use a map of headers instead of a list, something like:

key = header, value = type. GetHeaders => return List<String>(headers.keySet())

So in my columns i could check the type to use some formated output values.


Edit with code :

Controller with an inner class containing headers (=fields) and a list of records. Some queries are created from values contained in a custom object TodoBlock__c, then they are used to fill the list "records".

public with sharing class ToDoBlockController{
public TodoBlock todoBlock      {get;set;}

public void initComponent(){
    // init todoblock
}

public class TodoBlock{
    // input
    public String        name       {get;set;}
    public String        query      {get;set;}
    public List<String>  headers    {get;set;}
    public Integer       queryLimit {get;set;}

    // calculation
    public List<SObject> records {get;set;}
    public Integer       count   {get;set;}
    public String        objType {get;set;}

    // modification
    public String        sortColumn     {get{ return sortColumn==null ? headers[0] : sortColumn; } set;}
    public boolean       isAscSort      {get{ return isAscSort==null ? true : isAscSort; }  set;}

    public TodoBlock(TodoBlock__c record, Integer queryLimit, String sortColumn, String isAscSortStr){ 
        // attributes initialization
    }
    public void runQueries(){
        // queries records
    }
}

}

Visualforce component containing the table.
I am having trouble displaying it correctly, anyway important part is under the 2 comments. Here i would like to format the value depending on its type. Value is record[header] result. Type can be anything.
I see 2 option :

  • I can get type from VF side => i create tags with conditions in rerender attribute
  • I need to store it somewhere in the controller => instead of String[] header I shoud use Map{String=>String} where key is header/field name and value is type

    0}">

    {!$ObjectType[todoBlock.objType].fields[header].label} rendered="{!todoBlock.sortColumn = header}" value="/s.gif"/>

                    <!-- 1st col = link -->
                    <apex:outputLink value="/{!rec.Id}" target="_blank" rendered="{!header == todoBlock.headers[0]}">{!rec[header]}</apex:outputLink>
    
                    <!-- other cols = normal -->
                    <apex:outputLabel rendered="{!header != todoBlock.headers[0]}">{!rec[header]}</apex:outputLabel>
                </apex:column>
                </apex:repeat>
    
            </apex:pageBlockTable>
        </apex:pageBlockSection>
    
2
  • 1
    you can try it out and post you code along with the problem you are facing. May 10, 2017 at 14:53
  • I found no way to do it with apex tags for the moment. I will try to handle this with the map but the project became very low priority.
    – Guillaume
    Aug 2, 2017 at 8:00

1 Answer 1

0

So I made a Map fieldTypeMap and a component to handle the date/datetime format

Here is what I did, maybe it will be usefull for someone else.

Controller

I added the map as an attribute of my inner class into the controller:

// header/type mapping
public Map<String,String> headerTypeMap {get;set;}

I initialize it at the end of the constructor, thanks to this.headers (array of string header/field name), after the queries, like this:

        // calculation :
        runQueries();

        // mapping
        this.headerTypeMap = new Map<String,String>();
        for(String field : this.headers){
            this.headerTypeMap.put(
                field,
                Schema.getGlobalDescribe().get(objType).getDescribe().fields.getMap().get(field).getDescribe().getType()+''
            );
        }

Visualforce component

Because I often need to format date and datetime I thought it could be a good idea to create a formating component So I made a quick and dirty one:

<apex:component controller="FormatedValueController">
<apex:attribute name="dateValue" 
    type="Date" 
    assignTo="{!inputDateValue}"
    description="input value to formatTodoBlock__c record that contains data" 
/>
<apex:attribute name="datetimeValue" 
    type="Date" 
    assignTo="{!inputDateTimeValue}"
    description="input value to formatTodoBlock__c record that contains data" 
/>

{!formatedvalue}

Controller:

public class FormatedValueController {
    public Date     inputDateValue {get;set;}
    public Datetime inputDateTimeValue {get;set;}

    public String getFormatedValue(){
        String formatedValue = '';
        formatedValue += inputDateValue == null ? '' : inputDateValue.format();
        formatedValue += inputDateTimeValue == null ? '' : inputDateTimeValue.format();
        return formatedValue;
    }
}

And a quick&dirty test class too (for code coverage only):

@isTest
global class FormatedValueController_test{
    static testMethod void FormatedValueController() {
        FormatedValueController c = new FormatedValueController();
        Test.startTest ();
        c.getFormatedValue();
        Test.stopTest();
    }
}

100% you-hou ;)

And finally ...

Main Component

Oddly I need to use "{!todoBlock.headerTypeMap[header]}" everywhere, where todoBlock is the instance of my innerclass and header the var of repeat on headers attribute (table with a dynamic number of columns).

I wanted to use an apex variable for each header, kind of:

<apex:variable var="type" value="{!todoBlock.headerTypeMap[header]}" />

but for an unknown reason it just display the last header value in every loop. For example if I have DATE, DATETIME, STRING, it displays STRING, STRING, STRING. Not a big deal to use the full code, it is just less readable.

So here it is :

<apex:outputLabel rendered="{!todoBlock.headerTypeMap[header]=='DATETIME'}">
    <c:FormatedValue datetimeValue="{!rec[header]}"/>
</apex:outputLabel>

<apex:outputLabel rendered="{!todoBlock.headerTypeMap[header]=='DATE'}">
    <c:FormatedValue dateValue="{!rec[header]}"/>
</apex:outputLabel>

<apex:outputLabel rendered="{!NOT(AND(todoBlock.headerTypeMap[header]=='DATETIME',todoBlock.headerTypeMap[header]=='DATE'))}">
    {!rec[header]}
</apex:outputLabel>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.