+ Start a Discussion
GoForceGoGoForceGo 

Creating an Editable Grid/Table using visual force

  How would I go about doing it?

The usage is as follows:

For example, if an account has 10 contacts, instead of editing one at a time. I want  to be  able to display a table of  with just First Name, Last Name, phone, e-mail, Title

The dataTable object - is there any option to create an editable grid?





jwetzlerjwetzler
Here's an example using pageBlockList, although you can use dataTable instead of pageBlockList (in which case you don't need the pageBlock / pageBlockButtons, just a save button somewhere in the form).
Code:
<apex:page standardController="account">
    <apex:form>
        <apex:pageBlock>
            <apex:pageBlockButtons>
                <apex:commandButton action="{!Save}" value="Save"/>
            </apex:pageBlockButtons>
            <apex:pageBlockList value="{!account.contacts}" var="contact">
                <apex:column headerValue="First Name"><apex:inputField value="{!contact.firstname}"/></apex:column>
                <apex:column headerValue="Last Name"><apex:inputField value="{!contact.lastname}"/></apex:column>
                <apex:column headerValue="Phone Number"><apex:inputField value="{!contact.phone}"/></apex:column>
                <apex:column headerValue="E-mail"><apex:inputField value="{!contact.email}"/></apex:column>
                <apex:column headerValue="Title"><apex:inputField value="{!contact.title}"/></apex:column>
            </apex:pageBlockList>
        </apex:pageBlock>
    </apex:form>
</apex:page>

 

GoForceGoGoForceGo
Thanks.

This does not work though. The problem is that the "Save" command is using "Accounts", not contacts, so when I change a name and save, it doesn't do anything.

Any thoughts?


GoForceGoGoForceGo
Anyone?

Can you make the standard controller for Account (in the example above) save contact data?

If not, do you implement a custom controller?

The general problem as follows:

You want to display a "related list" Data table and edit the records of that object and save it. 

The Apex Page itself would take the record id of the record that has the related list (e.g account for showing related contacts).

How do you get apex page to save the related list data?

Ron HessRon Hess
Here is a sample of a page and controller extension that does what you describe ( grid edit records in a related list )

consider the (custom) object model of   parent and master-detail,  in this case Consulting_Project and Deliverable

page
Code:
<apex:page standardController="Consulting_Project__c" extensions="deliverablesController">
 <style>
.pbBody td {
 border-color: #E3DEB8;
 border-style: none none solid;
 border-width: medium medium 2px;
 padding-bottom: 4px;
 padding-top: 4px;
 width: 85px;
}
.pbBody input   { width: 105px;}
.pbBody .nameColumn { width: 125px;}
.hdr     {;}
</style>
<apex:form>
 <apex:messages />

 <apex:sectionHeader title="Deliverables for" subtitle="{!Consulting_Project__c.name}" />
 <apex:pageBlock title="Edit Deliverables">
  <apex:pageBlockButtons>
   <apex:commandButton action="{!saveChanges}" value="Save"
    rerender="main" status="ajaxStatus" />
   <apex:commandButton action="{!cancel}" value="Cancel" />
  </apex:pageBlockButtons>
  <apex:actionStatus id="ajaxStatus" startText="Updating schedules...">
   <apex:facet name="stop">
   <apex:outputPanel id="main">
    <table>
    <tr>
     <apex:repeat value="{!headers}" var="h">
      <td class="hdr">{!h}</td>
     </apex:repeat>
    </tr>

    <apex:repeat value="{!Deliverables}" var="a">
     <tr>
      <td ><apex:inputField value="{!a.name}" /></td>
      <td><apex:inputField value="{!a.Deliverable_Type__c}" /></td>
      <td><apex:inputField value="{!a.Completion_Date__c}" /></td>
      <td><apex:inputField value="{!a.Actual_Hours__c}" /></td>
      <td><apex:inputField value="{!a.Actual_Charge__c}" /></td>
      <td><apex:inputField value="{!a.Assigned_To__c}" /></td>
     </tr>
    </apex:repeat>
    </table>
   </apex:outputPanel>
   </apex:facet>
  </apex:actionStatus>
 </apex:pageBlock>
</apex:form>
</apex:page>

 

and now the extension ==> deliverablesController

Code:
public class deliverablesController {
  
  // Constructor
 public deliverablesController(ApexPages.StandardController controller) {
  this.proj = (Consulting_Project__c)controller.getSubject();
  
     this.delivers = [ SELECT 
      d.SystemModstamp, d.Name, 
      d.LastModifiedDate, d.LastModifiedById, d.LastActivityDate, 
      d.IsDeleted, d.Id, d.Deliverable_Type__c, d.CreatedDate, d.CreatedById, 
      d.Consulting_Project__c, d.Completion_Date__c, d.Assigned_To__c, d.Actual_Hours__c, 
      d.Actual_Charge__c 
      FROM 
      Deliverable__c d 
      WHERE 
      d.consulting_project__c = :proj.id ];
 }
 
 // Action Method called from page button
 public pagereference saveChanges() { 
  upsert this.delivers;
  return null;
 }
 
 // Action Method called from page link
 public pagereference newDeliverable() { 
  deliverable__c d = new deliverable__c();
  d.consulting_project__c =this.proj.id; 
  delivers.add( d );
  return null;
 }
 
 // public Getter to provide table headers 
 public string[] getheaders() { return new string [] 
  {'Name','Type','Competion Date','Actual Hours', 'Actual Charge',
   'Assigned To' } ; }
 
 // public Getter to list project deliverables
 public deliverable__c[] getDeliverables() { 
  return this.delivers; 
 } 
 
 // class variables
 Consulting_Project__c proj;
 deliverable__c[] delivers; 
}

 

you can (easily) modify this to work with accounts and contacts.
change  Consulting_Project__c ==> account
change deliverable__c ==> contact

then modify the fields as you require.

to invoke this, besure to add ?id=your_account_id or the controller extension will not find any data in the constructor


GoForceGoGoForceGo
Okay, I did this and it works great.

I want to accomplish something else:

In the example above, pretend deliverable_type__c is a pick list. I want to break up the table into multiple tables based on different values of the pick list. It works great as follows if I know the pick list values and number of pick list items ahead of time.

How do I do it if picklist values and the number of pick list items are not known ahead of time?

Apex Page code:

Code:
<apex:page StandardController="ssoft__Audit__c" extensions="lineItemController">
<apex:SectionHeader title="Supplier: {!ssoft__Audit__c.ssoft__Supplier__r.Name} , Audit Date: {!ssoft__Audit__c.ssoft__Audit_Date__c}, Type: {!ssoft__Audit__c.ssoft__Audit_Type__c} " />
<apex:pageBlock title="Audit Items">
<apex:form>
<apex:commandButton action="{!saveAllChanges}" value="Save All Changes"/>
<apex:pageBlockSection title="Quality Management" collapsible="true" columns="1">
<apex:commandButton action="{!saveQAChanges}" value="Save QM Changes"/>
<br/>
<apex:dataTable value="{!qauditItems}" var="audit" cellPadding="4" border="1" styleClass="list">
<apex:column>
<apex:facet name="header">Audit Item</apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Item_Number__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Item Description </apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Item_Description__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Suggested Evidence</apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Typical_Evidence__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Maximum Score</apex:facet>
<apex:outputText value="{!audit.ssoft__Maximum_Score__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Audit Criterion</apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Criterion__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Self Rating</apex:facet>
<apex:inputField id="selfrating" value="{!audit.ssoft__Self_Rating__c}" />
</apex:column>

<apex:message> for="selfrating" </apex:message>

<apex:column>
<apex:facet name="header">Self Rating Comment</apex:facet>
<apex:inputField value="{!audit.ssoft__Self_Rating_comment__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Auditor Rating</apex:facet>
<apex:inputField value="{!audit.ssoft__Auditor_Rating__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Auditor Rating Comment</apex:facet>
<apex:inputField value="{!audit.ssoft__Auditor_Rating_Comment__c}"/>
</apex:column>
</apex:dataTable>
</apex:PageBlockSection>

<apex:pageBlockSection title="Occupational Health and Safety" columns="1">
<apex:commandButton action="{!saveOHSChanges}" value="Save OHS Changes"/>
<br/>
<apex:dataTable value="{!oauditItems}" var="audit" cellPadding="4" border="1" styleClass="list" >
<apex:column>
<apex:facet name="header">Audit Item</apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Item_Number__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Item Description </apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Item_Description__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Suggested Evidence</apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Typical_Evidence__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Maximum Score</apex:facet>
<apex:outputText value="{!audit.ssoft__Maximum_Score__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Audit Criterion</apex:facet>
<apex:outputText value="{!audit.ssoft__Audit_Criterion__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Self Rating</apex:facet>
<apex:inputField value="{!audit.ssoft__Self_Rating__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Self Rating Comment</apex:facet>
<apex:inputField value="{!audit.ssoft__Self_Rating_comment__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Auditor Rating</apex:facet>
<apex:inputField value="{!audit.ssoft__Auditor_Rating__c}"/>
</apex:column>
<apex:column>
<apex:facet name="header">Auditor Rating Comment</apex:facet>
<apex:inputField value="{!audit.ssoft__Auditor_Rating_Comment__c}"/>
</apex:column>
</apex:dataTable>
</apex:pageBlockSection>
</apex:form>
</apex:pageBlock>



</apex:page>

 
Controller Code:

Code:
public class lineItemController {

public lineItemController(ApexPages.StandardController controller) {
this.audit = (Audit__c)controller.getSubject();
this.qauditItems = [ SELECT
q.Audit_Item_Number__c, q.Audit_Item_Description__c,
q.Audit_Typical_Evidence__c, q.Audit_Criterion__c,
q.Maximum_Score__c,
q.Self_Rating__c, q.Self_Rating_comment__c,
q.Auditor_Rating__c, q.Auditor_Rating_comment__c
FROM
audit_item__c q
WHERE
q.audit__c = :audit.id and q.Audit_Item_Type__c = 'Quality Management' ORDER BY q.Audit_Item_Number__c];

this.oauditItems = [ SELECT
q.Audit_Item_Number__c, q.Audit_Item_Description__c,
q.Audit_Typical_Evidence__c, q.Audit_Criterion__c,
q.Maximum_Score__c,
q.Self_Rating__c, q.Self_Rating_comment__c,
q.Auditor_Rating__c, q.Auditor_Rating_comment__c
FROM
audit_item__c q
WHERE
q.audit__c = :audit.id and q.Audit_Item_Type__c = 'OHS' ORDER BY q.Audit_Item_Number__c];
}

//Action Method called from page button
public pagereference saveQAChanges() {
upsert this.qauditItems;
return null;
}
//Action Method called from page button
public pagereference saveOHSChanges() {
upsert this.oauditItems;
return null;
}
//Action Method called from page button
public pagereference saveAllChanges() {
saveQAChanges();
saveOHSChanges();
return null;
}
// public Getter to list project deliverables
public audit_item__c[] getqauditItems() {
return this.qauditItems;
}
// public Getter to list project deliverables
public audit_item__c[] getoauditItems() {
return this.oauditItems;
}
// class variables
Audit__c audit;
Audit_item__c[] qauditItems;
Audit_item__c[] oauditItems;

}

 




GoForceGoGoForceGo
I guess if I could get to Metadata, I can do this.

Is there a way to get to metadata for an object in Apex - doesn't seem like DescribeSObject exists in Apex?





GoForceGoGoForceGo
Assuming Meta Data is not available, I just created a unique list of Declaration_Type_c/Audit_Item_Type__c by just iterating through the deliverables/Audit_Item__c. I am assuming there is a max of ten values in pick list and displaying 10 tables.

BTW, I did it with tabpanel and tab - even cooler! It also looks like x-cel spread sheet now!


VisualForceVisualForce

Hi..

    I am in same situation...

But I need inputtext and selectlist instead of inputfield (in the above Ron Hess code)...  I able to retrive all records and display it in a table..  How to save edited inputtext value and change select list value in a database...

That is the cells are input text and select list values... I couldnt set the setter method for individual cells... The setter method is working only for last row.. That is its retrive and set last row only...

How to retrive all rows records....

Any one have the sample code please post it...

GoForceGoGoForceGo
Why does it matter whether it is input text or select list?

As long as you have an array (delivers in Ron Hess example and qauditItems, oAuditItems in my example) that maps to the table and as long as you update the entire table you should be fine.




VisualForceVisualForce

Thanks for ur reply...

       How to assign setter method for each row in a datatable.. If I am using setter method I able to get last row value only...

If u  have sample code please reply me...

GoForceGoGoForceGo

I don't user setter method for each row. Just an action method for entire table.

In my example:

//Action Method called from page button
public pagereference saveQAChanges() {
upsert this.qauditItems;
return null;
}

As you will see qauditItems is the array which stores all the entries in the table.



VisualForceVisualForce
Thanks for ur reply...
 
          But I dont know how to implement it...
 
Can u post ur full code....
CEPCEP

@Ron Hess - this is a great example. Thank You!

 

One question... how do you add a record for the Deliverables grid?

 

The comments in your controller state, "...Action method called from page link...".  Which page link are you referring to?

CEPCEP
FYI - I figured it out... Just need to add another <apex:commandButton> for that action.

Again, thanks for a great example!
Roger WickiRoger Wicki
Could anyone post a screenshot on how this would look like? I may be looking to accomplish something similar...
Thanks
Evan DonovanEvan Donovan

A simpler way might be to use the open-source code available here: https://github.com/Up2Go/visualforce-table-grid

(I haven't tested it yet myself, but it looks good.)

Brian Cherry FWIBrian Cherry FWI
Any ideas on how to add a row and delete a row using this structure?
robbie waderobbie wade
Evan D (or anyone) - can you give me an example of how to actually use the open source code you posted above in an  apex page?  I am new and cant seem to get it working with my custom object.  Any help would be GREATLY appreciated! 
Evan DonovanEvan Donovan
robbie wade: I haven't used the github code I linked but it has usage details on the page. It looks like it has a type parameter which would take  the machine name of the object.

If you want something simpler and don't need to put it in Visualforce, I recommend the GridBuddy app: https://appexchange.salesforce.com/listingDetail?listingId=a0N30000003IkInEAK. That's what I use now. You can get a few licenses for free if you are with a nonprofit.
robbie waderobbie wade
thanks Evan.  I must have missed the usage details page.  I will go back and look again.  I appreciate the speedy reply sir!
robbie waderobbie wade
Oh, btw, I did look at GridBuddy and a few others however I need to create my grid on a VF page and so similar to my original post, I'm having trouble finding out how to implement that or if its even possible using an app.
Sai Ram ASai Ram A
@robbie wade, were you able to bulid such page?

Did any once find a solution for this?

Thank you