function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
GoForceGoGoForceGo 

Using GetRecordIds in a VisualForce page

I can use the listViews tag to show the list views in a VF page

Is there any way of getting the records similar to GetRecordIds?

How would I link a VF button to these records?



dchasmandchasman
Support for Visualforce based set oriented override pages and custom buttons etc will be included in Winter '09 and is something we're very excited about! We specifically did not just port the getrecordIds() concept into Visualforce because we wanted to provide something much more powerful.
GoForceGoGoForceGo
Thanks Doug.

Sounds like I am stuck with with S-controls for this.



TehNrdTehNrd

GoForceGo wrote:
Thanks Doug.

Sounds like I am stuck with with S-controls for this.


Well... sandboxes will be upgraded to Winter 09 this weekend and then the production upgraded first/second week of October.
GoForceGoGoForceGo
Well it's not too bad then!



dchasmandchasman
Right - this seasonal naming gets folks every time - think of it like when you go to buy a new car - at this time of the year all the dusty old '08s are on sale and those shiny new '09s are being unloaded from the car carriers :-)
GoForceGoGoForceGo
In Winter 09, I am trying a custom list controller based on the code in the VF page developer guide, but it does not work.

It basically says Sobject.name does not exist (for o.name). The getRecords on StandardSetcontroller returns a list of SObjects, not opportunities.

Is there a workaround?

Code:
public class opportunityList2Con {
public ApexPages.StandardSetController setCon {
get {
if(setCon == null) {
setCon = new ApexPages.StandardSetController(Database.getQueryLocator([select
name,closedate from Opportunity]));
}
return setCon;
}
set;
}
}
The following Visualforce markup shows how the custom controller from above can be used in a page:
<apex:page controller="opportunityList2Con">
<apex:pageBlock >
<apex:pageBlockTable value="{!setCon.records}" var="o">
<apex:column value="{!o.name}"/>
<apex:column value="{!o.closedate}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:pag


 

dchasmandchasman
Yeah there is a bug in the example - that would have never worked. When you use <apex:page recordSetvar> we automatically create a type safe collection property but when you create your own instance of the standard list controller you will need to also expose a property of type List<Your SObjectType goes here> and return a casted ref from getRecords() like this:

Code:
<apex:page controller="opportunityList2Con">
<apex:pageBlock >
<apex:pageBlockTable value="{!opps}" var="o">
<apex:column value="{!o.name}"/>
<apex:column value="{!o.closedate}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

public class opportunityList2Con {
public List<Opportunity> opps {
get {
if (opps == null) {
Apexpages.StandardSetController setCon = new ApexPages.StandardSetController(Database.getQueryLocator([select name,closedate from Opportunity]));
opps = (List<Opportunity>)setCon.getRecords();
}

return opps;
}

private set;
}
}

Now I am assuming that you are at the beginning of building something more complicated and just using the standard list controller directly in your page like this does not do what you want?

Code:
<apex:page standardController="Opportunity" recordSetVar="opps">
    <apex:pageBlock >
        <apex:pageBlockTable value="{!opps}" var="o">
            <apex:column value="{!o.name}"/>
            <apex:column value="{!o.closedate}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

 




Message Edited by dchasman on 10-02-2008 03:58 PM

Message Edited by dchasman on 10-02-2008 04:00 PM
GoForceGoGoForceGo
Yes,  I am building something more complicated....I was just playing around with functionality to see what it can do...

Is there anyway of dynamically typecasting the objects? Something like?


Code:
   public List<Dynamic SObjectType> objectList{
        get {
            if (ObjectList == null) {
                Apexpages.StandardSetController setCon = new ApexPages.StandardSetController(Database.getQueryLocator(<Dynamic SQL here asking for Name of object>));
                objectList = (List<Dynamic SObjectType>)setCon.getRecords();
            }
        
            return objectList;
        }
        
        private set;
    }

 
Here is what I am trying to do. I am hoping to be able to use Dynamic Apex along with List controller pages......if you have any thoughts.

I have a written a mini workflow engine inside Salesforce - it essentially let's you describe a sequence of steps, some optional to do some work - it is like an Approval engine, except that Approval engine doesn't have a bunch of functionality I want (Duration of approval task being a key one).  I create a task for each step, when the step is completed, I created a task for next step etc...

I want to be able to mass open workflows for any object in the system. The open workflow object will hard code field names for each of the object types in the system...

So here is what I do. So first, I ask the user what object they want to open work flow for (using DescribeGlobal call and create a selectList for it).
Based on the type of object selected, I would use code like above to create a list controller for that object and have the user select it.
Finally I want to use dynamic Apex to set the value of "Open Workflow.FieldName" to be the ID of the objects that I am  opening it for...


dchasmandchasman
VF value and action bindings require statically typed things to bind to. An approach that often works is to add a layer of abstraction between (Facade/Adapter if you are into design patterns)  VF bindings and the actual objects you are trying to wire up. In this case I suspect there is a common shape that you can wrap your sobjects in and you can leverage an apex code class based wrapper or a set of wrappers that all implement a common apex code interface.

We have a feature under development called Component Binding lets you go completely dynamic but its going to be a few seasons before you get your hands on that functionality I am sorry to say Component Binding is what you absolutely need if you want to be able to dynamically add components to the server side component tree.

Finally, there is always the option to push more of this to the client/browser - VF can easily produce various dynamic client side representations directly using some of the lower level components like <apex:repeat> and if this is primarily view only data with an action or link of some kind this can be pretty easy to accomplish. At the end of the day you are always free to get as close to the metal of the browser as you want.
GoForceGoGoForceGo
Thanks That's where I was begining to go...write some wrapper classes....

When a custom list controller is defined, each of the elements in the list is shown in a table/list (using /dataTable/PageBlockTable/dataList tags).

Is there a standard way to show the "Action" against each item - Check Box, Edit, Del" for each of the rows in the table?

StandardSetController has methods such as getSelected, getListViewOptions and getFilterId. When a custom list controller is defined, how is one supposed to use them? With the listView tag?










sspssp
How to use
getSelected  sObject[]Returns the list of sObjects that have been selected.
 
with custom controllers?
 
 
GoForceGoGoForceGo
Doug,

It would be very helpful if you could clarify if the following can be accomplished with new list controller or some other mechanism.

I have two objects A and B. I have a  junction object called AB which maps n-to-n mapping between A and B.

For a given A object instance , I want to be able to mass create instances of AB object by selecting the B object instances that I want to associate with this A object instance.

Here are the steps in my mind.

  1. On the detail page of A object with the related AB list, I add a button called "Mass Add B"
  2. When they click this button, I want to be on a page similar to the list views for B object, where the user can select the records that they want to AB Objects for. The user should be able to select from predefined List Views.
  3. On this page, I want a button called "Mass Add" which will save these new records to junction object table AB
Is there any functionality in list controllers that accomplishes this?

I need to be able to define the VF page for steps 2/3 above:

  1. Doesn't seem like I can use the standard tag <apex:Listviews>  to accomplish this, since this tag cannot be embedded in a form. My form will have a button called "Mass Add". Even if I could, how would I get the selected items in the VF page?
  2. If I use a custom controller with a StandardSetController member variable, how do I create a check box for selected items? How does this checkbox interact with getSelected function? Or do I have to go back and write a wrapper class (here is the thread) around the B object with a boolean variable to identify selected. If I have to use wrapper class, I obviously cannot use StandardSetController, since it relies on sObjects, not generic wrapper class objects?
  3. Can I use the ListViewOptions along with StandardSetController in this case?






mtbclimbermtbclimber
Yes. You can leverage the StandardSetController but for the selection capability you will need to implement a wrapper class which provides the relevant boolean property for selection similar to the thread you referenced.

The trick is in your controller you need to use the getRecords() collection and convert it to your wrappers and then bind the table to the wrapper collection accordingly.

I've been working on a sample that will be up on the wiki/blog soon I hope as I can imagine this to be a somewhat common pattern. It works but there is some trickiness to maintaining a unique collection (only one instance of the AB combo) within the UI which also raises a functional question of whether you want duplicates in the DB or not.

Here's the relevant snippet from my controller, I am binding my apex:pageBlockTable to the caseSelects collection:

Code:
    
    public List<CaseSelect> getCaseSelects() {
        if(caseSelects == null) {
            caseSelects = new List<CaseSelect>();
            List<Case> cases = (List<Case>) setCon.getRecords();

            for(Case c:cases) {
                CaseSelect cs = new CaseSelect(c);
                for(CaseSelect sc:selectedCases) {
                    if(sc.theCase.id == c.id) {
                        cs.selected = true;
                        break;
                    }
                }
                caseSelects.add(cs);                    
            }
        
        }
        
        return caseSelects;
    }
    
    public List<CaseSelect> caseSelects;
    
    public class CaseSelect {
        public Case theCase { get; private set; }
        public boolean selected { get; set; }
        
        public CaseSelect(Case c) {
            theCase = c;
        } 
    }

 


GoForceGoGoForceGo
Andrew,

Thanks.

I am not clear how this would work.

If pageBlockTable is bound to caseSelects, how is setCon (case collection) used?

Is setCon (case collection) bound to anything in the VF page?

As I mentioned, I really want to use "the list views" - which would imply that I want to be able
to select the record set based on ListViews - I was hoping the use StandardSetController to be able to use
getListViewOptions, getFilterId

One way I can think of is to define a field called "selected" in the object (case) itself instead
of defining a wrapper.  Then I can bind SetCon directly to the SObjects.However,forcing such a field doesn't seem like a good way to do it.

And I think you bring up a good issue about duplicates. (I assume  your inner loop in the code above trying to do something about duplicates)

Assuming I want unique records, I want to be NOT show the B records for which AB records already exist.

I thought that filtering them out during initiation of SetCon would do it - but it doesn't work. The system shows filtered
record initially, but as soon as a view is picked, it shows all records.

As an example, let's say a list View called "Cases open more than 7 days" has 10 records. However
3 of them already have the "AB" record. When I initiate the setCon, I filter them out. When i
select the list option "Case Open more than 7 days", I again see 10 records!





Message Edited by GoForceGo on 10-19-2008 10:53 PM
GoForceGoGoForceGo
In the example below, when I select a list view filter, the pageBlockTable does NOT refresh.


Code:
<apex:page controller="supplierListCon">
 <apex:pageBlock >
  <apex:form id="theForm">
   <apex:panelGrid columns="2">
    <apex:outputLabel value="View:" />
    <apex:selectList value="{!setCon.filterId}" size="1">
     <apex:actionSupport event="onchange" rerender="list" />
     <apex:selectOptions value="{!setCon.listviewoptions}" />
    </apex:selectList>
   </apex:panelGrid>
   <apex:panelGrid columns="2">
    <apex:commandLink action="{!setCon.previous}">Previous</apex:commandlink>
     <apex:commandLink action="{!setCon.next}">Next</apex:commandlink>
   </apex:panelGrid>
   <apex:pageBlockTable value="{!SupplierSelects}" var="s" id="list">
    <apex:column value="{!s.theSupplier.name}" />
    <apex:column value="{!s.theSupplier.sbase__DUNS_Number__c}" />
   </apex:pageBlockTable>
  </apex:form>
 </apex:pageBlock>
</apex:page>

 
Controller:

Code:
public class opportunityList2Con {

       public ApexPages.StandardSetController setCon {
            get {
               if(setCon == null) {
                       setCon = new ApexPages.StandardSetController(Database.getQueryLocator([select name,sbase__DUNS_Number__c from sbase__Supplier__c]));               
                }
               return setCon;
              }
            set;
       }
       public List<sbase__Supplier__c> getSuppliers() {
              return (List<sbase__Supplier__c>)setCon.getRecords();
       }
      
       public List<SupplierSelect> getSupplierSelects() {
          
         if(SupplierSelects == null) {
            SupplierSelects = new List<SupplierSelect>();
            List<sbase__Supplier__c> Suppliers = (List<sbase__Supplier__c>) setCon.getRecords();
            for(sbase__Supplier__c c:Suppliers) {
                SupplierSelect cs = new SupplierSelect(c);
                SupplierSelects.add(cs);                   
            }
        }
        return SupplierSelects;
    }
   
    public List<SupplierSelect> SupplierSelects;
   
    public class SupplierSelect {
        public sbase__Supplier__c theSupplier { get; private set; }
        public boolean selected { get; set; }
       
        public SupplierSelect(sbase__Supplier__c c) {
            theSupplier = c;
        }
    }

   
}

 However, if I use the Supplier list (without the wrapper), the filters DOES work.


Code:
<apex:page controller="supplierListCon">
 <apex:pageBlock >
  <apex:form id="theForm">
   <apex:panelGrid columns="2">
    <apex:outputLabel value="View:" />
    <apex:selectList value="{!setCon.filterId}" size="1">
     <apex:actionSupport event="onchange" rerender="list" />
     <apex:selectOptions value="{!setCon.listviewoptions}" />
    </apex:selectList>
   </apex:panelGrid>
   <apex:panelGrid columns="2">
    <apex:commandLink action="{!setCon.previous}">Previous</apex:commandlink>
     <apex:commandLink action="{!setCon.next}">Next</apex:commandlink>
   </apex:panelGrid>
   <apex:pageBlockTable value="{!Suppliers}" var="s" id="list">
    <apex:column value="{!s.name}" />
    <apex:column value="{!s.sbase__DUNS_Number__c}" />
   </apex:pageBlockTable>
  </apex:form>
 </apex:pageBlock>
</apex:page>

 





mtbclimbermtbclimber
When you postback to the controller the page is just going to get the same SupplierSelect collection from viewstate.  If you add an action to your controller that sets that collection to null and call it from your actionSupport component it should work.
GoForceGoGoForceGo
Thanks!

Now it works.

However, doesn't seem like the initial filter that I might apply is respected.

As an example if I restrict the records to those starting with an 'A', the initial list seems to be okay. if I change the list view options to "All", it pulls all the records from the database.


Code:
       public ApexPages.StandardSetController setCon {
            get {
               if(setCon == null) {
                    setCon = new ApexPages.StandardSetController(Database.getQueryLocator([select name,sbase__DUNS_Number__c from sbase__Supplier__c where Name like 'A%']));                
                }
               return setCon;
              }
            set;
       } 


If I use the alternate constructor where I fetch the records first and then pass them to constructor, the refreshes don't happen when I change the list view.

Code:
                    List<sbase__Supplier__c> MySuppliers = [select name,sbase__DUNS_Number__c from sbase__Supplier__c Where Name like 'A%'];
setCon = new ApexPages.StandardSetController(MySuppliers);

 
Also, note that if I set the initial filter as a limit, the system crashes when I try to select a specific list view. The specific list view uses the filter "Name starts with A". Seems like logic internally is trying
to append the where clause.


Code:
                    setCon = new ApexPages.StandardSetController(Database.getQueryLocator([select name,sbase__DUNS_Number__c from sbase__Supplier__c limit 20]));                

 
I get the crash:

sbase__Supplier__c.Name ASC limit 20 WHERE ((Name LIKE 'A%')) ^ ERROR at Row:1:Column:106 unexpected token: WHERE









Message Edited by GoForceGo on 10-20-2008 09:55 AM

Message Edited by GoForceGo on 10-20-2008 10:01 AM
mtbclimbermtbclimber
When you change the filter it will change the filter - not apply a union.

As for the latter issue, just make sure you have a where clause in the query even if it doesn't have any effect, like where id = null, while we get a resolution to this known issue.
GoForceGoGoForceGo
I had to use the same trick (nulling out SupplierSelects) for "Next" and "Previous". Also to save the entire list of selected items (user might go back and forth from one page to another), I had to create a Set where I store all the selected items across pages.

I am now writting another controller to "Mass Edit" existing AB records. If i have 100's of AB records, I want to paginate, If I have 30 records to edit, they all show up on the same page - I though the default was 20 or 25.

I also tried using the Page Size Extension controller does not seem to work.


Code:
public class tenPageSizeExt {
public tenPageSizeExt(ApexPages.StandardSetController controller) {
controller.setPageSize(10);
}
}

 
Controller:
Code:
<apex:page standardController="Opportunity" recordSetVar="opportunities"
tabStyle="Opportunity" extensions="TenPageSizeExt">
<apex:form >
<apex:pageBlock title="Edit Stage and Close Date" mode="edit">
<apex:pageMessages />
<apex:pageBlockButtons location="top">
<apex:commandButton value="Save" action="{!save}"/>
<apex:commandButton value="Cancel" action="{!cancel}"/>
</apex:pageBlockButtons>
            <apex:panelGrid columns="2">
                <apex:commandLink action="{!previous}">Previous</apex:commandlink>
                    <apex:commandLink action="{!next}">Next</apex:commandlink>
            </apex:panelGrid>
<apex:pageBlockTable value="{!selected}" var="opp">
<apex:column value="{!opp.name}"/>
<apex:column headerValue="Stage">
<apex:inputField value="{!opp.stageName}"/>
</apex:column>
<apex:column headerValue="Close Date">
<apex:inputField value="{!opp.closeDate}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>




 



Message Edited by GoForceGo on 10-20-2008 11:55 AM
MarkL.ax269MarkL.ax269
Any updates on this?  I was glad to find this thread because it's exactly the kind of page I'm trying to create and having a lot of trouble with, this A-AB-B relationship.  Were you able to leverage the list view selections?  I'm trying to work with what you're posted, but having trouble presenting a selectable list and then getting a handle on the user's selections.

Mark
GoForceGoGoForceGo
Here is some code to select records on a page.

You will have to add code for creating the junction object records.

Code:
<apex:page controller="MaterialListCon">
    <apex:pageBlock >
        <apex:form id="theForm">
            <apex:panelGrid columns="2">
                <apex:outputLabel value="View:" />
                <apex:selectList value="{!setCon.filterId}" size="1">
                    <apex:actionSupport action="{!updateMaterialSelects}" event="onchange" rerender="list" />
                    <apex:selectOptions value="{!setCon.listviewoptions}" />
                </apex:selectList>
            </apex:panelGrid>
            <apex:panelGrid columns="2">
                <apex:commandLink action="{!previous}">Previous</apex:commandlink>
                    <apex:commandLink action="{!next}">Next</apex:commandlink> 
            </apex:panelGrid>
            <apex:pageBlockTable value="{!MaterialSelects}" var="s" id="list">
                <apex:column headerValue="Select">
                   <apex:inputCheckBox value="{!s.selected}"/> 
                </apex:column>
                <apex:column value="{!s.theMaterial.name}" />
                <apex:column value="{!s.theMaterial.CAS__c}" />
            </apex:pageBlockTable>
        </apex:form>
    </apex:pageBlock>
</apex:page>

 
Code:
public class MaterialListCon {

       public ApexPages.StandardSetController setCon {
            get {
               if(setCon == null) {
                    //List<Material__c> MyMaterials = [select name,DUNS_Number__c from Material__c];
                    //setCon = new ApexPages.StandardSetController(MyMaterials);   
                    setCon = new ApexPages.StandardSetController(Database.getQueryLocator([select name,CAS__c, from Material__c]));                            
                }
               return setCon;
              }
            set;
       } 
       public List<Material__c> getMaterials() {
           return (List<Material__c>)setCon.getRecords();
       }
       
      
       public List<MaterialSelect> getMaterialSelects() {
        
         if(MaterialSelects == null) {
            MaterialSelects = new List<MaterialSelect>();
            List<Material__c> Materials = (List<Material__c>) setCon.getRecords();
            for(Material__c c:Materials) {
                MaterialSelect cs = new MaterialSelect(c);
                if (EntireSelectedList.contains(c.id)) {
                 cs.selected = true;
                }
                MaterialSelects.add(cs);                    
            }
        }
        return MaterialSelects;
      }
      
       public void  updateEntireSelectedList() {
        
          if (MaterialSelects == null) return;
          for (MaterialSelect ss:MaterialSelects) {
            if (ss.selected) {
             //update if it exists
             EntireSelectedList.add(ss.theMaterial.id);
            } else {
             //remove if present
             EntireSelectedList.remove(ss.theMaterial.id);
            }
          }
       }
       
    
       public PageReference updateMaterialSelects() {
            updateEntireSelectedList();
            MaterialSelects = null;
            return null;
       }

       public PageReference Next() {
            updateEntireSelectedList();
            MaterialSelects = null;
            setCon.next();
            return null;
       }

       public PageReference Previous() {
         updateEntireSelectedList();
            MaterialSelects = null;
            setCon.previous();
            return null;
       }    
       
    public List<MaterialSelect> MaterialSelects; 
    
    public Set<Id> EntireSelectedList = new Set<Id> ();
    
    public class MaterialSelect {
        public Material__c theMaterial { get; private set; }
        public boolean selected { get; set; }
        
        public MaterialSelect(Material__c c) {
            theMaterial = c;
        } 
    }

}

 



MarkL.ax269MarkL.ax269
Thank you very much!  I'm happy to report that after much trial and error, I was able to create the kind of "A-select-B" page I was looking for using just a visualforce page - selections will require a controller extension, but I've got a handle on that.  I'm sure this is something others are doing too.  It's a detail page with an "unrelated list" consisting of completely unrelated objects.  In my case I'm relating Products to a set of Variable Masters (the unrelated list), creating a subset of Product Variables.  I wanted to launch the page from the Product record but since the standard controller is the Variable Master, I can't use a visualforce page button.  I used a URL button from the Product page like so:

Code:
/apex/varListPage?scontrolCaching=1&myproduct={!Product2.Id}

Then the page is very straightforward.  This one doesn't select, but implementing your selection method above in a controller extension will do the trick.  The list is driven by the list views set up on the Variable Master tab, renders fast and I could actually let the users edit the variables right in the list if I wanted.  Very nice.
Code:
<apex:page id="thePage" standardController="Variable_Master__c" recordSetVar="Variable_Masters" tabStyle="Product2">
   <apex:form >
       <apex:detail subject="{!$CurrentPage.parameters.myproduct}" relatedlist="false"></apex:detail>
       <apex:pageBlock >
           <apex:outputLabel value="View: " for="viewlist"></apex:outputLabel>
           <apex:selectList id="viewlist" value="{!filterid}" size="1">
               <apex:actionSupport event="onchange" rerender="listview"></apex:actionSupport>
               <apex:selectOptions value="{!listviewoptions}"/>
           </apex:selectList>
           
           <apex:pageBlockTable value="{!variable_masters}" var="var" id="listview">
               <apex:column value="{!var.name}"/>
               <apex:column headerValue="id">
                   {!var.Variable_Field_ID__c}
               </apex:column>
               <apex:column headerValue="Type">
                   {!var.Type__c}
               </apex:column>
           </apex:pageBlockTable>
       </apex:pageBlock>
   </apex:form>
</apex:page>

 



Message Edited by MarkL on 11-13-2008 04:14 PM
MarkL.ax269MarkL.ax269
In case someone else can use this, I've learned a lot about list controllers in the last few days.  I've created a page that allows a user to select records from a completely unrelated object, and then create a junction record between them.  This selectable list is driven by the standard list views on the Variable Management tab so reconfiguring the list is easy, but it actually displays the wrapper class objects containing the selected boolean.  It also gets around the current list view limitation that you can't pre-filter the list of records before displaying - you just filter the wrappers instead, and the standard list view acts as your SOQL query!  I'm not sure, but I'll bet you could leverage this design pattern with enhanced lists too...going to try that when I have a little extra time.

The first non-rendered pageBlockTable is necessary because it determines the fields available for the displayed wrapper table.  Adding a field to the vmlist table makes it available to the wrapper table, essentially functioning as the SOQL query.  The getListViewItems method in my controller then filters for only selectable items and displays the result.  One strange thing I learned, I initially wanted to display all variables and just disable the checkbox on items already present.  Apparently there's some kind of problem disabling checkboxes when displaying things like this, got a server error every time, when the only difference was adding the disabled="true" attribute.  So I just filtered instead, which I like better.

Code:
<apex:page id="thePage" standardController="Variable_Master__c" recordSetVar="Variable_Masters" tabStyle="Product2" extensions="variableMasterController">
 <apex:detail subject="{!$CurrentPage.parameters.recordid}" relatedlist="false" title="false"></apex:detail>
 <apex:relatedList id="setupVars" list="Setup_Variables__r" subject="{!$CurrentPage.parameters.recordid}"/>
 <apex:form >
  <apex:pageBlock >
   <apex:pageMessages />
   <apex:selectList id="viewlist" value="{!filterid}" size="1">
    <apex:actionSupport action="{!updateListViewItems}" event="onchange" rerender="vmlist,wrapperlist"/>
    <apex:selectOptions value="{!listviewoptions}"/>
   </apex:selectList>
   &nbsp;
   <apex:commandButton action="{!addSetupVar}" value="Add Selected Variables" oncomplete="top.location.reload(true);"/>
   <br/>
   <apex:outputText ><i>Note: Setup variables already selected are not listed.</i></apex:outputText>
    
   <apex:pageBlockTable value="{!variable_masters}" var="vm" id="vmlist" rendered="false">
                <apex:column headerValue="id">
     {!vm.Variable_Field_ID__c}
    </apex:column>
    <apex:column headerValue="Name">
     {!vm.Name}
    </apex:column>
    <apex:column headerValue="Type">
     {!vm.Type__c}
    </apex:column>
    <apex:column headerValue="Team Profile">
     <apex:outputField value="{!vm.Team_Profile__c}"/>
    </apex:column>
    <apex:column headerValue="Default Value">
     {!vm.Default_Value__c}
    </apex:column>
   </apex:pageBlockTable>
   
   <apex:pageBlockTable value="{!ListViewItems}" var="wrapper" id="wrapperlist" width="100%">
    <apex:column headerValue="Select">
                   <apex:inputCheckBox selected="{!wrapper.selected}"/> 
                </apex:column>
                <apex:column headerValue="id">
     {!wrapper.theItem.Variable_Field_ID__c}
    </apex:column>
    <apex:column headerValue="Name">
     {!wrapper.theItem.Name}
    </apex:column>
    <apex:column headerValue="Type">
     {!wrapper.theItem.Type__c}
    </apex:column>
    <apex:column headerValue="Team Profile">
     <apex:outputField value="{!wrapper.theItem.Team_Profile__c}"/>
    </apex:column>
    <apex:column headerValue="Default Value">
     {!wrapper.theItem.Default_Value__c}
    </apex:column>
   </apex:pageBlockTable>
   
   <!-- <apex:outputText id="debugText" value="List: {!ListViewItems}" /> -->
   
  </apex:pageBlock>
 </apex:form>
</apex:page>

 And some of the supporting controller.
Code:
public map<String, String> mapURLParams = new map<String, String>(); //map of parameters from the calling URL
 public list<Variable_Master__c> listObjects = new list<Variable_Master__c>(); //list of the actual objects which will be placed in the wrapper class
 public list<ViewItem> listViewItems; //list of all wrapper objects in the current list view - the selectable list
    public set<Id> setSelectedItems = new set<Id> (); //set to contain the selected items - set is used to prevent duplicates
    private ApexPages.StandardSetController ssc; //reference to the list coming from the standard list controller
    private set<Id> setupVars; //set to contain filtered variables that will noy be shown in the final wrapper table
    
    //constructors
    public variableMasterController() {

    }
    
    public variableMasterController(ApexPages.StandardSetController controller) {
     this.ssc = controller;
     this.listObjects = (list<Variable_Master__c>)controller.getRecords();
     this.mapURLParams = ApexPages.currentPage().getParameters();
     if (mapURLParams.get('type') == 'product') {
      this.setupVars = getSetupVars(mapURLParams.get('recordid'));
     }
    }
        
    //wrapper class to contain the selection boolean
    //all objects returned from the list view are loaded to this class
    public class ViewItem {
        
        public Variable_Master__c theItem { get; private set; } //the item itself
        
        public boolean selected { get; set; } //whether or not it has been selected
        
        public ViewItem(Variable_Master__c item) { //constructor
            theItem = item;
        }
         
    }
    
    //method to create the wrapper objects from the current list objects
    public list<ViewItem> getListViewItems() {
     listObjects = (list<Variable_Master__c>)ssc.getRecords();
     if (listViewItems == null) {
      listViewItems = new list<ViewItem>();
      for (Variable_Master__c obj : listObjects) {
       ViewItem vi = new ViewItem(obj);
       //pre-filter the list, removing variables that are already in the setup list
       if (!setupVars.contains(obj.Id)) {
        if (setSelectedItems.contains(obj.Id)) {
         vi.selected = true;
        }
        listViewItems.add(vi);
       }
      }
     }
     return listViewItems;
    }

 


GoForceGoGoForceGo

I want to be able to perform some background action when a user selects a bunch of records and then clicks a button on a list view button(e.g update a checkbox field on all of them).

 

Before StandardSetController, you would call getRecordIds  and use AJAX tool kit. I used to call some server code using sforce.apex.execute.

 

Is there anyway of doing this with StandardSetController? 

 

Note that when the user clicks the list button, I don't want to go to another VF page - I just want to execute some server code and stay on the same page. StandardSetcontroller works when you have another visual force page in the middle. 

 

 

mtbclimbermtbclimber

No there is no way to do this with the standardsetcontroller today. 

 

One question I have though is how do you indicate status/success/failure of the operation to the user?

GoForceGoGoForceGo

Today with Javascript, status/error is a pop-up alert box - it can be a pain if multiple errors are found.

 

Ideally messages would be shown in-line next to the record.

 

However, an pop-up page might be another option - similar to what mass edit from list does today.

 

 

GoForceGoGoForceGo

Andrew,


Appreciate your thoughts on this.

 

http://community.salesforce.com/sforce/board/message?board.id=Visualforce&message.id=14914

 

 

DowithforceDowithforce

Hi all,

 

I successfully implement pagination with StandardSetController for custom controller, but 

if I have more than 10000 records. I am getting

 

Too many query locator rows: 10001

 

I know this is WELL KNOWN ISSUE(for huge data), can you please tell me how to handle this case?

 

I have post so many time about Apex batching like it is working in APIs, but what about apex lanuage.

 

Is there any solution to deal with huge data(I mean more than 100000 records) in Apex?

 

 

Thanks 

DowithforceDowithforce

Hi all, 

 

I got 10000 records in StandardSetController, How I will get next 10000 records using it? and so on

 

 

Thanks 

UmapenUmapen

Is it possible to post final code which can process 10000 records.

 

I am pretty confused after reading the post. Currently I have  little over 5000 records that I am able display using javascript pagination. But do not know how to process selected records.

 because I am not storing the query results

  I am doing -

    

return Database.query(cntSOQL); //about statement return 5434 contacts

 

DowithforceDowithforce

Hello Umpen,

 

Code as follows:

 

VF page

apex:page Controller="LeadlistController" recordSetVar="{!leads}">
<apex:form >
<style>
.dateFormat{display:none;}
</style>
<style type="text/css">
.h1 {background-color:#D8D8D8;
border-width: 2px;
border-spacing: 4px;
padding: 2px;
border-style: inset;
border-color: :#D8D8D8;
border-collapse: separate;}

</style>
<apex:pageBlock >
<apex:pagemessages />

<apex:dataTable width="100%" border="1" id="DataTable" value="{!leads}" var="o" id="opp_table" style="font-size:11px;text-align: center; vertical-align:top;word-wrap: break-word;height: 20px;" headerClass="h1"
columnsWidth="150,70,130,70">

<apex:column >
<apex:facet name="header"><b>Name</b></apex:facet>
<apex:OutputText value="{!o.name}" />
</apex:column>

<apex:column >
<apex:facet name="header"><b>Title</b></apex:facet>
<apex:OutputText value="{!o.title}" />
</apex:column>

<apex:column >
<apex:facet name="header"><b>Email</b></apex:facet>
<apex:OutputText value="{!o.email}" />
</apex:column>

<apex:column >
<apex:facet name="header"><b>Phone</b></apex:facet>
<apex:OutputText value="{!o.phone}" />
</apex:column>


</apex:dataTable>
<apex:panelGrid columns="2" style="font-weight: bold;">
<apex:commandLink action="{!previous}" rendered="{!hasPrevious}"><font color="blue">Previous</font></apex:commandLink>
<apex:commandLink action="{!next}" rendered="{!hasNext}"><font color="blue">Next</font></apex:commandLink>
</apex:panelGrid>
</apex:pageBlock>
</apex:form>
</apex:page>

 

Controller code:

 

 

public class LeadlistController  {
   
     
    public Boolean hasNext {get; private set;}
    public Boolean hasPrevious {get; private set;}

 
    public ApexPages.StandardSetController setCon {
                get {
                       if(setCon == null)
                       {
                               String query = 'select name, title, email, phone from lead order by name ASC LIMIT 10000';
                                setCon = new ApexPages.StandardSetController(Database.getQueryLocator(query));
                                setCon.setPageSize(100);                               
                                setNextPrevious();
                       }
                       
                        return setCon;
                    }
                set;
        }
    public List<Lead> getleads()
    {
             return (List<Lead>) setCon.getRecords();
    }
       
     
   
    public PageReference next()
    {
        if (hasNext)
            setCon.next();
        setNextPrevious();
        return null;
    }
    public PageReference previous()
    {
        if (hasPrevious)
            setCon.previous();
        setNextPrevious();
        return null;
    }
    private void setNextPrevious()
    {
        if (setCon.getHasNext()) {
            hasNext = true;
        }
        else {
            hasNext = false;
        }
        if (setCon.getHasPrevious()) {
            hasPrevious = true;
        }
        else {
            hasPrevious = false;
        }       
    }
   
   
}

 

Do with force!

 

Thanks

UmapenUmapen

Thanks for the prompt response. 

What am I doing wrong? I am getting error at line 27

Error: Compile Error: unexpected token: 'List' at line 27 column 21 

public class cntlistController { public Boolean hasNext {get; private set;} public Boolean hasPrevious {get; private set;} String Role = 'Primary Contact'; set<Id>eligibleHotels = new Set<Id>(); public ApexPages.StandardSetController setCon { get { if(setCon == null) { for (Account_Group_Relationship__c p:[Select a.Id FROM Account_Group_Relationship__c ar, ar.Merchandising__r a, ar.Substore__r s WHERE ar.Status__c = 'Pending' AND s.Id = :substoreid]) { eligibleHotels.add(p.Property__r.Id); //make list of eligible accounts } String cntSOQL='Select c.Id, c.Name, c.Email, c.Account.Id, c.Account.Name, c.Account.Rating__c, c.Account.special__c, c.Account.Lose__c FROM Contact c WHERE c.email !=null AND c.Role__c INCLUDES (:role) AND c.Opt_out_email__c !=TRUE AND c.Account.ID NOT IN :eligibleHotels ORDER BY c.Account.Name DESC LIMIT :hotellimit '; setCon = new ApexPages.StandardSetController(Database.getQueryLocator(cntSOQL)); setCon.setPageSize(150); setNextPrevious(); } return setCon; } set; } public List<contact> getcnts() { return (List<contact> setCon.getRecords(); }

 

 

DowithforceDowithforce

 

 

check missing closing ) bracket

 

 return (List<contact> setCon.getRecords();

 

 your stament should like

 

return (List<contact> setCon.getRecords());

 

UmapenUmapen

Thanks,

How can I capture selected records from this long list. Do I have to write wrapper class?

I have input checkbox to process selected records?

Appreciate any suggestions.

GoForceGoGoForceGo

You should redesign your UI so that a user doesn't have to select from 10,000 records. Create a UI where user first filters down the record. How does a user every go around selecting 5 out of 10,000 records?

 

 

UmapenUmapen

I am providing filter through jscript and css. User will be presented with 200 records at a time and select the once that needs processing.

all I need is to know which contact user selected in every page

Appreciate your suggestions

UmapenUmapen
Now I got my record size to 2000 any suggestions on how I can get pagination working with wrapper class?
hamayoun65hamayoun65

GoForceGo, thank you very much for your solution, it works perfectly!  You just saved me countless hours of trial and error!

@altius_rup@altius_rup

First of all, thanks GoForceGo for your example.

 

It's very easy to adapt : I jest replaced your Material__c custom object with mine, displayed Id and Name attributes, and was up and going in minutes with your custom VF page.

 

When I display the page normally (https://c.cs7.visual.force.com/apex/test), all is fine :

- data is displayed in the table

- the filter list is populated correctly

 

If I change the way I call the page by passing an ID parameter in the URL, like this (https://c.cs7.visual.force.com/apex/test?id=a08M00000030LkU), it's not OK :

- data is displayed in the table

- the filter list only contains 1 item called 'All', and its id is '000000000000000AAA'

 

What magic is going on behind the scenes ?  This is a NO GO for me ...

Rup

@altius_rup@altius_rup

Answering my own post - SOLVED :

 

PROBLEM : When I call the test page with an id parameter, it seems to think that it is an object detail page and make StandardSetController behave strangely, for filters, as if it did not accept to show any filters for this page.

https://c.cs7.visual.force.com/apex/test?id=a08M00000030LkU

 

SOLUTION : I set up a very short VF page accepting id as a param, which then calls my test page passing the id value into another parameter, called something else (cerepid in my case).

https://c.cs7.visual.force.com/apex/passthrough?id=a08M00000030LkU

which calls

https://c.cs7.visual.force.com/apex/test?cerepid=a08M00000030LkU

 

When my test page receives the id value in the cerepid parameter, it behaves correctly, displaying the right list of filters.

 

Have a good day, reader,

Rup

success22success22

Hello,

 

I am facing same problem. 

 

mtbclimber,

 

Could you  please explain that where 'SelectedCases' variable is coming from? Please let me know.