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
MRosiMRosi 

StandardSetController and How to use standard CSS

Hello,

 

I want to print a list of a customer's recent jobs (Job__c) on a public page with the percent completed for each.

I made VF with a dataTable, and a StandardSetController. But found these problems and am stuck.

 

- ORDER BY clause is being ignored. Displays ASC no matter whether I choose ASC or DESC.

WHERE clause is being ignored. Displays all records even if I choose CreatedDate > :mydate)

- CSS. I want to make it look just like ordinary Salesforce list views as shown when you click on an object's tab. I was able to put some css into the VF file to make it look better than raw text but still it is not what I want. (I used some css found in this forum as a test but don't want to use it in production). I've tried various things and can't figure out what the right way to do it is.

- Pagination. I have seen some roll your own pagination posted but I just want to use that standard Salesforce stuff.

- Sorting. Ideally it would display as DESC (latest job at top) and also you could click on a column header to sort the column. Not critical though.

 

I am thinking right now that the problem is StandardSetController which was said to be buggy in 2008.. so maybe I should make a list of lists of strings? Still, how do you in fact make a list view of custom objects that has the salesforce look? It is said you should copy their stylesheets but in fact these are old articles, the urls don't exist anymore, and it bears no resemblence to the source code of salesforce pages. Where are the dataTable styles for example?

 

Here is what I have now, including the VisualForce page, Apex list controller, and a screenshot.  (Please ignore the Japanese, there is translation in the attached screenshot if you care.)

 

Thank you very much for your help. I think I can at the minimum deal with what I have here though I'd like it to look like Salesforce.

 

<!-- OBSOLETE apex:page controller="factoryCustPortal" -->
<apex:page standardcontroller="Job__c" extensions="factoryCustPortal_JobStatusDisplay" 
		   recordSetVar="recentjobs" 
		   language="ja" tabStyle="Job__c"
		   showHeader="true" standardStylesheets="true">
		   <!--   -->

<style type="text/css">
<!-- Note this borrowed css is just for debugging not production. I want to use the Salesforce stylesheet. -->
.newspaper-head
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 14px;
	color: #039;
}
.newspaper-a
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 12px;
	margin: 45px;
	width: 480px;
	text-align: left;
	border-collapse: collapse;
	border: 1px solid #69c;
}
.newspaper-a th
{
	padding: 12px 17px 12px 17px;
	font-weight: normal;
	font-size: 14px;
	color: #039;
	border-bottom: 1px dashed #69c;
}
.newspaper-a td
{
	padding: 7px 17px 7px 17px;
	color: #669;
}
.newspaper-a tbody tr:hover td
{
	color: #339;
	background: #d0dafd;
}

.newspaper-b
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 12px;
	margin: 45px;
	width: 480px;
	text-align: left;
	border-collapse: collapse;
	border: 1px solid #69c;
}
</style>

  <h1>顧客用ポータルサイト</h1>
    <apex:pageBlock >    
        現在の処理状況
        <br/>
        <apex:pageMessages />
        <br/><br/>
		<apex:outputPanel id="panel" layout="block" >
            <div width="500" class="listBody">
              <apex:dataTable value="{!recentjobs}" var="c" id="jobtable"  
              	cellpadding="3" cellspacing="3" styleClass="newspaper-a">
              	
                <apex:facet name="caption" ><span style="font-size:14px; color:#039; font-family:Lucida Sans Unicode,Lucida Grande,Sans-Serif;">入庫ジョブ一覧表</span></apex:facet>
                <!--  <apex:facet name="header">最近の処理状況</apex:facet>  -->
                <!--  <apex:facet name="footer">table footer</apex:facet>  -->
                <apex:column style="text-align:center">
                        <apex:facet name="header">ジョブID</apex:facet>
                        <apex:outputField value="{!c.name}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">作成日</apex:facet>
                        <apex:outputField value="{!c.CreatedDate}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">ベール数</apex:facet>
                        <apex:outputField value="{!c.Item_Count__c}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">処理完了度</apex:facet>
                        <apex:outputField value="{!c.Percent_Done__c}"/>
                </apex:column>
              </apex:dataTable>
            </div>
            
            <apex:outputText >{!teststr}</apex:outputText>
        </apex:outputPanel>

        <apex:outputText >
            <br/><br/>
            <hr/>
            <table border="0" cellspacing="2" cellpadding="2">
             <tr>
                 <td align="left"><apex:outputLink value="/apex/factory_public_top">Return to Top Page</apex:outputLink></td>
             </tr>
             
            </table>
        </apex:outputText>

    </apex:pageBlock>
    
</apex:page>

 

 

public class factoryCustPortal_JobStatusDisplay {

    // Customer has logged in by providing their password.
    // Now display a list of the customer's recent jobs, showing %completed for each.
    // Note this does not check which System or Factory.

    private Integer monthsback = -2;
    private Customer__c cust;
    public String custpass;
    public String teststr {get; set;}

    public ApexPages.StandardSetController jobs {
        get {
            if (jobs == null)  {
 	      if (checkcust()) {
	        Date timeago = Date.today().addMonths(monthsback);
                Job__c[] joblist = [select name,Customer__c,CreatedDate,Percent_Done__c,Item_Count__c
        	        	from Job__c where Customer__c = :cust.id 
        	                and CreatedDate > :timeago
                	        order by name asc];	
               	return new ApexPages.StandardSetController(joblist);
	      } // if valid cust
 	      else {
		  return null; // die with message in teststr. Haven't tested to see if this works yet.
 	      }
            } // if jobs is null
            return jobs;
        }
        private set;
    }

    public List<Job__c> getfactoryCustPortal_JobStatusDisplay() {
        return (List<Job__c>)jobs.getRecords();
    }

    public factoryCustPortal_JobStatusDisplay(ApexPages.StandardSetController controller) {
        // this.Customer__c = (Customer__c)controller.getRecord();
    }

    public Boolean checkcust() {
        // Get password from hidden input field, validate, then set cust or die
        
        // Get user's password from query params
        PageReference thisPage = ApexPages.currentPage();
        custpass = thisPage.getParameters().get('custpass'); // password is posted from an apex:inputHidden field
        
        // Get Customer from pass
        try {
            cust = [select Id,Name,Portal_Password__c from Customer__c where Portal_Password__c = :custpass limit 1];
            String custname = cust.name;
            teststr = custname + '  (' + cust.id +')';
            return true;
        }
        catch (Exception e) {
            String badpass = 'Bad Password. Please contact your account executive.';
            teststr = badpass;
        }
        return false;
    }

}

 

Screenshot

 

(p.s. I got the following message but it seems okay and I can't tell what the forum software deleted..)

"Your post has been changed because invalid HTML was found in the message body. The invalid HTML has been removed. Please review the message and submit the message when you are satisfied."

 

Best regards,

 

Matt

Best Answer chosen by Admin (Salesforce Developers) 
MRosiMRosi

I just want to post for completeness and to resolve this issue.

 

The "ignores where clause" issue was solved. It arose due to faulty controller implementation. When I rewrote it based on the idea of MVC it worked.

 

The misunderstanding was compounded because the VF page made it look like it was working, due to declaring a recordsetvar. Probably other people who found that where clause gets ignored (back in 2009 or so) hit the same problems.

 

The CSS issue is not resolved yet and have decided not part of the scope anymore.

 

In addition, Premier Support provided me some tips after I discovered this which I may use. Basically instead of trying to get CSS to work in an apex:dataTable use an apex:pageBlockTable instead, and use the apex:page standardStylesheets attribute which when set to true will read in the latest Salesforce stylesheets.

 

http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_pageBlockTable.htm

http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_page.htm

 

Also there is no documentation on stylesheets apparently and you have to look at sourcecode yourself to figure it out for the following code: (and stylesheets are subject to change at arbitrary times)

 

<apex:dataTable value="{!account}" var="acc" styleClass="list">

You can do something like this:
<link  href="/sCSS/20.0/sprites/Theme3/ja/gc/common.css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet" type="text/css" />

but this is mandatory:
<apex:page showHeader="false" standardStylesheets="false">

 

 

Current code follows.

 

public class factoryCustPortal_JobStatusDisplay {

    // Customer has logged in by providing their password.
    // The password is posted to us in parameter "custpass", which we have to validate.
    // Display a list of the customer's recent jobs, showing %completed for each.
    // Note this does not check which System or Factory.
    // This covers all jobs with owner being the customer who inputted the password.
    // So it works for any kind of processing.
    // Job__c.Memo__c is not shown to customer since this is an internal memo.
    // Only shows limited history (daysback) so internal users should use the related Report.

	private Integer daysback = -60; // A number less than zero. -30 means all bales from today to 30 days ago.
    private Customer__c cust;
    public String custpass { get; set; } // iruma: xtngokruo2
    public String custname { get; set; }
    public String teststr  { get; set; }
    private Boolean badpass; 
    private PageReference thisPage;

    public ApexPages.StandardSetController con {
        get {
            if (con == null)  {
 				if (checkcust()) {
	                Date timeago = Date.today().addDays(daysback); // -30 means 30 days ago from today
    	            Job__c[] joblist = [select name,Customer__c,Customer__r.name,CreatedDate,Percent_Done__c,Item_Count__c
        	                            from Job__c where Customer__c = :cust.id 
            	                        and CreatedDate > :timeago
                	                    order by name desc
                	                    ];					
                	con = new ApexPages.StandardSetController(joblist);
                	return con;
 				} // if valid cust
 				else {
 					return null; // die with message in teststr TODO TESTME
 				}
            } // if con is null
            return con;
        }
        set;
    }

    public List<Job__c> getRecentJobs() { //WAS List<Job__c>getfactoryCustPortal_JobStatusDisplay()
		if (con == null) {
			if (!badpass) teststr = 'お客様は最近の作業記録がありません。';
			return null;
		}
        return (List<Job__c>)con.getRecords();
    }

	public factoryCustPortal_JobStatusDisplay(ApexPages.StandardSetController controller) { // constructor
        teststr = '';
        custname = '';
        badpass = false;

        thisPage = ApexPages.currentPage();
        custpass = thisPage.getParameters().get('custpass');
        
    	if (!checkcust()) {
    		teststr = 'お客様のパスワードは間違っています。'; // doesn't display
    		badpass = true;
    	}
    }

    public Boolean checkcust() {
        // Get password from hidden input field, validate, then set cust or die
        
        // Get user's password from query params
        String errstr = 'パスワードを入力してください。';

        //OUT (done in constructor) custpass = thisPage.getParameters().get('custpass'); //DEBUG this.pass = 'nyjwnbmy8k';
        if (custpass == null) {
        	teststr = errstr;
        	badpass = true;
        	return false;
        }
		custpass = custpass.trim();       	
        if (custpass == '') {
        	teststr = '-- ' + errstr;
        	badpass = true;
        	return false;
        }

        // Get Customer from pass
        try {
            cust = [select Id,Name,Portal_Password__c from Customer__c where Portal_Password__c = :custpass limit 1];
            custname = cust.name + '様 ';
            return true;
        }
        catch (Exception e) {
            //not shown ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.FATAL, badpass);
            //            throw new MyException(badpass,e);
        	teststr = 'お客様のパスワード記録が見つかりません。アカウント管理者にご連絡ください。';
	        return false;
        }
    }

}

 

<!-- OBSOLETE apex:page controller="factoryCustPortal" -->
<apex:page standardcontroller="Job__c" extensions="factoryCustPortal_JobStatusDisplay" 
		   recordSetVar="recentjobs" 
		   language="ja" tabStyle="Job__c"
		   showHeader="true" standardStylesheets="true">
		   <!--   -->

<style type="text/css">
.newspaper-head
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 14px;
	color: #039;
}
.newspaper-a
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 12px;
	margin: 45px;
	width: 480px;
	text-align: left;
	border-collapse: collapse;
	border: 1px solid #69c;
}
.newspaper-a th
{
	padding: 12px 17px 12px 17px;
	font-weight: normal;
	font-size: 14px;
	color: #039;
	border-bottom: 1px dashed #69c;
}
.newspaper-a td
{
	padding: 7px 17px 7px 17px;
	color: #669;
}
.newspaper-a tbody tr:hover td
{
	color: #339;
	background: #d0dafd;
}

.newspaper-b
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 12px;
	margin: 45px;
	width: 480px;
	text-align: left;
	border-collapse: collapse;
	border: 1px solid #69c;
}
</style>

  <h1>顧客用ポータルサイト</h1>
    <apex:pageBlock mode="maindetail">    
        現在の処理状況
        <br/>
        <apex:pageMessages />
        <br/><br/>
		<apex:outputPanel id="panel" layout="block" >
            <div width="500" >
              <apex:dataTable value="{!recentjobs}" var="c" id="jobtable"  styleClass="newspaper-a"
              	cellpadding="3" cellspacing="3" >
              	
                <apex:facet name="caption" ><span style="font-size:14px; color:#039; font-family:Lucida Sans Unicode,Lucida Grande,Sans-Serif;">
                {!custname}入庫ジョブ一覧表</span></apex:facet>
                <!--  <apex:facet name="header">最近の処理状況</apex:facet>  -->
                <!--  <apex:facet name="footer">table footer</apex:facet>  -->
                <apex:column style="text-align:center">
                        <apex:facet name="header">ジョブID</apex:facet>
                        <apex:outputField value="{!c.name}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">作成日</apex:facet>
                        <apex:outputField value="{!c.CreatedDate}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">ベール数</apex:facet>
                        <apex:outputField value="{!c.Item_Count__c}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">処理完了度</apex:facet>
                        <apex:outputField value="{!c.Percent_Done__c}"/>
                </apex:column>
              </apex:dataTable>
            </div>
            
            <apex:outputText >{!teststr}</apex:outputText>
        </apex:outputPanel>

        <apex:outputText >
            <br/><br/>
            <hr/>
            <table border="0" cellspacing="2" cellpadding="2">
             <tr>
                 <td align="left"><apex:outputLink value="/apex/factory_public_top">ポータルのトップ・ページに戻る</apex:outputLink></td>
             </tr>
             
            </table>
        </apex:outputText>

    </apex:pageBlock>
    
</apex:page>

 

apex:pageBlockTable 

apex:page 

All Answers

MRosiMRosi

I just want to post for completeness and to resolve this issue.

 

The "ignores where clause" issue was solved. It arose due to faulty controller implementation. When I rewrote it based on the idea of MVC it worked.

 

The misunderstanding was compounded because the VF page made it look like it was working, due to declaring a recordsetvar. Probably other people who found that where clause gets ignored (back in 2009 or so) hit the same problems.

 

The CSS issue is not resolved yet and have decided not part of the scope anymore.

 

In addition, Premier Support provided me some tips after I discovered this which I may use. Basically instead of trying to get CSS to work in an apex:dataTable use an apex:pageBlockTable instead, and use the apex:page standardStylesheets attribute which when set to true will read in the latest Salesforce stylesheets.

 

http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_pageBlockTable.htm

http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_page.htm

 

Also there is no documentation on stylesheets apparently and you have to look at sourcecode yourself to figure it out for the following code: (and stylesheets are subject to change at arbitrary times)

 

<apex:dataTable value="{!account}" var="acc" styleClass="list">

You can do something like this:
<link  href="/sCSS/20.0/sprites/Theme3/ja/gc/common.css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet" type="text/css" />

but this is mandatory:
<apex:page showHeader="false" standardStylesheets="false">

 

 

Current code follows.

 

public class factoryCustPortal_JobStatusDisplay {

    // Customer has logged in by providing their password.
    // The password is posted to us in parameter "custpass", which we have to validate.
    // Display a list of the customer's recent jobs, showing %completed for each.
    // Note this does not check which System or Factory.
    // This covers all jobs with owner being the customer who inputted the password.
    // So it works for any kind of processing.
    // Job__c.Memo__c is not shown to customer since this is an internal memo.
    // Only shows limited history (daysback) so internal users should use the related Report.

	private Integer daysback = -60; // A number less than zero. -30 means all bales from today to 30 days ago.
    private Customer__c cust;
    public String custpass { get; set; } // iruma: xtngokruo2
    public String custname { get; set; }
    public String teststr  { get; set; }
    private Boolean badpass; 
    private PageReference thisPage;

    public ApexPages.StandardSetController con {
        get {
            if (con == null)  {
 				if (checkcust()) {
	                Date timeago = Date.today().addDays(daysback); // -30 means 30 days ago from today
    	            Job__c[] joblist = [select name,Customer__c,Customer__r.name,CreatedDate,Percent_Done__c,Item_Count__c
        	                            from Job__c where Customer__c = :cust.id 
            	                        and CreatedDate > :timeago
                	                    order by name desc
                	                    ];					
                	con = new ApexPages.StandardSetController(joblist);
                	return con;
 				} // if valid cust
 				else {
 					return null; // die with message in teststr TODO TESTME
 				}
            } // if con is null
            return con;
        }
        set;
    }

    public List<Job__c> getRecentJobs() { //WAS List<Job__c>getfactoryCustPortal_JobStatusDisplay()
		if (con == null) {
			if (!badpass) teststr = 'お客様は最近の作業記録がありません。';
			return null;
		}
        return (List<Job__c>)con.getRecords();
    }

	public factoryCustPortal_JobStatusDisplay(ApexPages.StandardSetController controller) { // constructor
        teststr = '';
        custname = '';
        badpass = false;

        thisPage = ApexPages.currentPage();
        custpass = thisPage.getParameters().get('custpass');
        
    	if (!checkcust()) {
    		teststr = 'お客様のパスワードは間違っています。'; // doesn't display
    		badpass = true;
    	}
    }

    public Boolean checkcust() {
        // Get password from hidden input field, validate, then set cust or die
        
        // Get user's password from query params
        String errstr = 'パスワードを入力してください。';

        //OUT (done in constructor) custpass = thisPage.getParameters().get('custpass'); //DEBUG this.pass = 'nyjwnbmy8k';
        if (custpass == null) {
        	teststr = errstr;
        	badpass = true;
        	return false;
        }
		custpass = custpass.trim();       	
        if (custpass == '') {
        	teststr = '-- ' + errstr;
        	badpass = true;
        	return false;
        }

        // Get Customer from pass
        try {
            cust = [select Id,Name,Portal_Password__c from Customer__c where Portal_Password__c = :custpass limit 1];
            custname = cust.name + '様 ';
            return true;
        }
        catch (Exception e) {
            //not shown ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.FATAL, badpass);
            //            throw new MyException(badpass,e);
        	teststr = 'お客様のパスワード記録が見つかりません。アカウント管理者にご連絡ください。';
	        return false;
        }
    }

}

 

<!-- OBSOLETE apex:page controller="factoryCustPortal" -->
<apex:page standardcontroller="Job__c" extensions="factoryCustPortal_JobStatusDisplay" 
		   recordSetVar="recentjobs" 
		   language="ja" tabStyle="Job__c"
		   showHeader="true" standardStylesheets="true">
		   <!--   -->

<style type="text/css">
.newspaper-head
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 14px;
	color: #039;
}
.newspaper-a
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 12px;
	margin: 45px;
	width: 480px;
	text-align: left;
	border-collapse: collapse;
	border: 1px solid #69c;
}
.newspaper-a th
{
	padding: 12px 17px 12px 17px;
	font-weight: normal;
	font-size: 14px;
	color: #039;
	border-bottom: 1px dashed #69c;
}
.newspaper-a td
{
	padding: 7px 17px 7px 17px;
	color: #669;
}
.newspaper-a tbody tr:hover td
{
	color: #339;
	background: #d0dafd;
}

.newspaper-b
{
	font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
	font-size: 12px;
	margin: 45px;
	width: 480px;
	text-align: left;
	border-collapse: collapse;
	border: 1px solid #69c;
}
</style>

  <h1>顧客用ポータルサイト</h1>
    <apex:pageBlock mode="maindetail">    
        現在の処理状況
        <br/>
        <apex:pageMessages />
        <br/><br/>
		<apex:outputPanel id="panel" layout="block" >
            <div width="500" >
              <apex:dataTable value="{!recentjobs}" var="c" id="jobtable"  styleClass="newspaper-a"
              	cellpadding="3" cellspacing="3" >
              	
                <apex:facet name="caption" ><span style="font-size:14px; color:#039; font-family:Lucida Sans Unicode,Lucida Grande,Sans-Serif;">
                {!custname}入庫ジョブ一覧表</span></apex:facet>
                <!--  <apex:facet name="header">最近の処理状況</apex:facet>  -->
                <!--  <apex:facet name="footer">table footer</apex:facet>  -->
                <apex:column style="text-align:center">
                        <apex:facet name="header">ジョブID</apex:facet>
                        <apex:outputField value="{!c.name}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">作成日</apex:facet>
                        <apex:outputField value="{!c.CreatedDate}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">ベール数</apex:facet>
                        <apex:outputField value="{!c.Item_Count__c}"/>
                </apex:column>
                <apex:column style="text-align:center">
                        <apex:facet name="header">処理完了度</apex:facet>
                        <apex:outputField value="{!c.Percent_Done__c}"/>
                </apex:column>
              </apex:dataTable>
            </div>
            
            <apex:outputText >{!teststr}</apex:outputText>
        </apex:outputPanel>

        <apex:outputText >
            <br/><br/>
            <hr/>
            <table border="0" cellspacing="2" cellpadding="2">
             <tr>
                 <td align="left"><apex:outputLink value="/apex/factory_public_top">ポータルのトップ・ページに戻る</apex:outputLink></td>
             </tr>
             
            </table>
        </apex:outputText>

    </apex:pageBlock>
    
</apex:page>

 

apex:pageBlockTable 

apex:page 

This was selected as the best answer
HariPHariP

Hi,

 

I have similar problem.

ORDER BY clause is ignored.

 

Can you please let me know if you resolved that issue?

 

Thanks

Hari