+ Start a Discussion
@altius_rup@altius_rup 

VisualForce transposed table - help with design options, please

Hi,

I need to display rows of a Salesforce object for data entry (eg product line items).

Each object has numerous fields (more than 20), and there are only a few rows (eg 5).

 

It would be much more practical my objects as columns in a VisualForce datatable, but that will be very complicated

- 1 or several transient classes to transform the Salesforce model into the displayed model

- 1 custom component for each different "complex" Salesforce type (date, lookup, selection list, etc.), since the VF page will no longer be displaying sObjects

- etc.

 

Is there a quicker way to benefit from all the standard Salesforce and VisualForce stuff (eg InputField instead of Inputtext) in a view where standard rows are transposed into columns ?

 

Thanks for any intelligent design ideas,

Rup

Best Answer chosen by Admin (Salesforce Developers) 
aballardaballard

I think you should be able to do it using a fieldset to specify the fields you want to display and iterating over the fieldset and rows.   Something like this....

 

<apex:dataTable value="{!$ObjectType.opportunitylineItem.fieldsets.myfieldset}" var="field">
<apex:repeat value="{!Opportunity.OpportunityLineItems}" var="item">
<apex:column value="{!item[field]}"/>
</apex:repeat>
</apex:dataTable>

All Answers

aballardaballard

You should still be able to use sobjects, inputField, etc   You will just need the controller code to provide the right object in the context. 

@altius_rup@altius_rup

Hi aballard, thanks for your answer.

 

I'm working with Opp Line Items, with many custom fields.

If I were displaying lines of Opp line Items in a DataTable, I would be using code such as :

 

<apex:pageBlockTable value="{!opplines}" var="row">

    <apex:column >
        <apex:outputField value="{!row.UnitPrice}">
            <apex:inlineEditSupport event="ondblClick" showOnEdit="saveButton" /> 
        </apex:outputField>
        <apex:facet name="header">TJM</apex:facet>
    </apex:column>

    <apex:column headerValue="Nb Jours" value="{!row.Quantity}"/>

    <!-- mois M01 à M12 -->
    <apex:column >
        <apex:outputField value="{!row.taux_mois01__c}">
            <apex:inlineEditSupport event="ondblClick" showOnEdit="saveButton" hideOnEdit="addButton"/> 
        </apex:outputField>
        <apex:facet name="header">{!nomMois01}</apex:facet>
    </apex:column>
    <apex:column >
        <apex:outputField value="{!row.taux_mois02__c}">
            <apex:inlineEditSupport event="ondblClick" showOnEdit="saveButton" hideOnEdit="addButton"/> 
        </apex:outputField>
        <apex:facet name="header">{!nomMois02}</apex:facet>
    </apex:column>

etc.

 

The nice thing here is that I am calling controller code on an sObject (Opp Line Item), and so I can use e.g. apex:outputField etc. and benefit from standard sObject rich data types (and input methods, eg for Dates, etc.)

 

Unfortunately, I need to transpose my Opp Line Items, and display them in colums, so each column will be a different Opp Line Item, and each row will be a different attribute : col 1 will contain the attribute name, col 2 will contain its value on oppli1, col 3 will contain its value on oppli2, etc.

 

To do this, I can only imagine to create a whole bunch of transient classe to describe each line (for each attribute) and hard code and manage custom components for data entry.

 

Do you think there could be a better way of doing this ?  Could I, somehow, build a DataTable and use an intelligent iterator to transpose my Opp Line Items into rows ?

 

I hope you can help,

Rup

 

aballardaballard

I think you should be able to do it using a fieldset to specify the fields you want to display and iterating over the fieldset and rows.   Something like this....

 

<apex:dataTable value="{!$ObjectType.opportunitylineItem.fieldsets.myfieldset}" var="field">
<apex:repeat value="{!Opportunity.OpportunityLineItems}" var="item">
<apex:column value="{!item[field]}"/>
</apex:repeat>
</apex:dataTable>

This was selected as the best answer
@altius_rup@altius_rup

Wow, that looks sexy : I'll give it a try, thanks,

Rup

@altius_rup@altius_rup

aballard, thanks, that was a great help  :smileytongue:

 

For readers, here is the full result :

<apex:page standardController="Opportunity" >
    <apex:form id="form" >
        <apex:pageBlock title="Transposed OppLineItems">
            <apex:pageMessages id="errors"/>

            <!-- <apex:pageBlockButtons location="top">
                <apex:commandbutton id="saveButton" action="{!mySave}" value="Save"/>
            </apex:pageBlockButtons> -->            

            <apex:DataTable value="{!$ObjectType.opportunitylineItem.fieldsets.IHM}" var="field">
                <apex:column headerValue="Attributs" value="{!field}"/>
                <apex:repeat value="{!Opportunity.OpportunityLineItems}" var="item">
                    <apex:column >
                        <apex:facet name="header">{!item['Destination__c']}</apex:facet>
                        <apex:outputField value="{!item[field]}">
                            <apex:inlineEditSupport event="ondblClick" showOnEdit="saveButton" /> 
                        </apex:outputField>
                    </apex:column>
    
                </apex:repeat>
            </apex:dataTable>
        </apex:pageBlock>
    </apex:form>

 </apex:page>

 You then define the IHM field set on OpportunityLineItem; you will need to customize mySave in an extension controller. 

 

Have fun, and thanks again,

Rup

 

@altius_rup@altius_rup

Well, saving the lines seemed simple :

 

First step : add the button at the top of the page :

    <apex:pageBlockButtons location="top">
        <apex:commandbutton id="saveButton" action="{!mySave}" value="Save"/>
    </apex:pageBlockButtons>            

 

Second step : create a controller extension :

<apex:page standardController="Opportunity" extensions="IHMController" standardStylesheets="false">

 

public class IHMController {
    
    private Opportunity               opp        { get; set; }
    private List<OpportunityLineItem> opplines   { get; set; }

    public IHMController(ApexPages.StandardController stdController) {
        opp   = (Opportunity)stdController.getRecord();
        try {
            opplines = [SELECT id, Base_Taux_VA__c, Volume_d_affaires_prevu__c FROM OpportunityLineItem WHERE OpportunityId = : opp.id];
            System.debug('#### opplines requete ='+opplines);
        } catch (DmlException ex) {
            ApexPages.addMessages(ex);
        }
    }      

    public PageReference mySave() {
        try {
            System.debug('#### opplines update ='+opplines);
            update opplines;
        } catch (DmlException ex) { 
            ApexPages.addMessages(ex);
        }
        return null;
    }
}

 

When I display an opp with opplines, I can edit the line content by double-clicking (thanks to inline editing) : great !

Then, when I click on Save, the lines are updated (seemingly) : the new values are displayed correctly on the screen.

However, if I refresh the screen, the lines are displayed with their old content !

 

It seems that the lines displayed on the screen after inline editing are not the lines (and values) saed into the database in the mySave method.

 

Any ideas, anyone ?

 

Rup

 

@altius_rup@altius_rup

OK, OK ... :smileysurprised:  Shame ! answer to myself :

 

I was displaying this in the VF page :

<apex:repeat value="{!$Opportunity.OpportunityLineItems}" var="item">

 and saving this in the controller :

update opplines;

 So I changed my VF page to display "{!opplines}".

NielsSchepersNielsSchepers

 Rupert,

 

Thanks for this great solution. Very close to what I am looking for. I also struggle to save changes made to the transposed table. And you last post does not work for me. Changing

<apex:repeat value="{!$Opportunity.OpportunityLineItems}" var="item">

 to

<apex:repeat value="{!opplines}" var="item">

 results in an error. Can you please help me?

 

Thanks a lot in advance!

@altius_rup@altius_rup

Did you create a property called "opplines" in your controller ?

 

In my case :

 

public List<ROS_CE_Line__c> Mylines {
    get { return (List<ROS_CE_Line__c>) CELines.getRecords(); }
    set;
}

 

where CELines is my StandardSetController :

 

public ApexPages.StandardSetController CELines {
    get {
        if (CELines == NULL) {
            CELines = new ApexPages.StandardSetController(Database.getQueryLocator(this.query));
            computeApprovals();
        }
        return CELines;
    }
    private set;
}

 

HTH,

Rup

NielsSchepersNielsSchepers

Thanks, my Apex skills are too limited to fit those lines into the code you provided earlier. But don't worry, I will need to get a developer anyway for other stuff. I got some good inspiration from your code, editing would just have been the cream on the cake. Thanks again!

salesforcesss_deveoper211salesforcesss_deveoper211

Hi All,

 

I am looking for similar requirement, here I managed to build transpose table but unable to save the data entered. So pls help.

 

Thanks.

 

Vf Page:

 

<apex:page standardController="Account" extensions="IHMController" standardStylesheets="false">
<apex:form id="form" >
<apex:pageBlock title="Account Contacts">
<apex:pageMessages id="errors"/>

<apex:pageBlockButtons location="top">
<apex:commandbutton id="saveButton" action="{!mySave}" value="Save"/>
</apex:pageBlockButtons>

<apex:DataTable border="1" value="{!$ObjectType.Contact.fieldsets.IHM}" var="field">
<apex:column headerValue="Attributs" value="{!field}"/>
<apex:repeat value="{!Account.Contacts}" var="item">
<apex:column >
<apex:facet name="header">{!item['Name']}</apex:facet>
<apex:outputField value="{!item[field]}">
<apex:inlineEditSupport event="ondblClick" showOnEdit="saveButton"/>
</apex:outputField>
</apex:column>

</apex:repeat>
</apex:dataTable>
</apex:pageBlock>
</apex:form>

</apex:page>

 

Controller:

 

public class IHMController {

private Account acc { get; set; }
private List<Contact> accContact { get; set; }

public IHMController(ApexPages.StandardController stdController) {
acc = (Account)stdController.getRecord();
try {
accContact = [SELECT id, Name, MobilePhone FROM Contact WHERE AccountId = : acc.id];
System.debug('#### opplines requete ='+accContact);
} catch (DmlException ex) {
ApexPages.addMessages(ex);
}
}

public PageReference mySave() {
try {
System.debug('#### opplines update ='+accContact);
update accContact;
} catch (DmlException ex) {
ApexPages.addMessages(ex);
}
return null;
}
}

@altius_rup@altius_rup

Hi Dave,

Have you defined a field set on Contact to list the fields you wish to display ?

Rup

salesforcesss_deveoper211salesforcesss_deveoper211

Hi Rup,

 

Yeah I have created the field set IHM under contact object. Even I can see the contact values in a table for any Account but only thing I am not able to update and save those contact values even after clicking save.

 

Thanks.