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
Michele Kleinhomer 10Michele Kleinhomer 10 

Loading Message on VF page

I would like to diisplay a loading message to let the users know the data is being loaded.  I found some code online that it sounds like should work, but I am not getting a message displayed.  The users click on a tab in Community to get the page to load.  I am hoping someone has a suggestion as to what I need to change to get a loading message.  Below is my code.
<apex:page showHeader="false" action="{!load}" standardStylesheets="true" standardController="account" extensions="DisplayContactExpertise" sidebar="false" docType="html-5.0" applyBodyTag="False" applyHtmlTag="False">

<style type="text/css">
        body {
    background-color: white;
}
        .pbTitle {
        white-space:nowrap;
        border:white;
    }
    </style>

    <form>
        
    <apex:repeat value="{!skills}" var="skill">
    <apex:pageBlock title="{!skill}" >
	<apex:pageBlockSection columns="1" >
            <apex:actionStatus id="mystatus" startText="Loading.....">
            <apex:facet name="stop">
            <apex:outputPanel id="out">

        
    <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px, 200px, 400px">
<apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}"> 
<apex:outputLink style="text-decoration:none" value="/{!contactskill.contact__r.ID}">{!contactskill.contact__r.name}</apex:outputLink>
</apex:column>
    <apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}"> 
<apex:outputLink style="text-decoration:none" value="/{!contactskill.contact__r.ID}">{!contactskill.contact__r.email}</apex:outputLink>
</apex:column>
<apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}"> 
<apex:outputLink style="text-decoration:none" value="/{!contactskill.contact__r.ID}">{!contactskill.contact__r.account.name}</apex:outputLink>
</apex:column>
    </apex:pageBlockTable>
                 </apex:outputPanel>
            </apex:facet>
            </apex:actionStatus>
</apex:pageBlockSection>
    </apex:pageBlock>
  </apex:repeat>
    </form>
</apex:page>

 
Alain CabonAlain Cabon
Hi,

You probably used this code: https://eltoro.secure.force.com/ShowAnImageWhileThePageIsLoading

You have forgotten the call of the action status itself. It is quite tricky. You always need a caller of the action status using the attribute : status.

When a page is loaded, the javascript function call at the end of the page is executed (here the call to the funciton sayHello). This javascript function call is associated with an action Function of your Visualforce named also sayHello which is real caller of the action status itself myStatus

<apex:form ID="TheForm">
<apex:actionStatus id="mystatus" startText="Loading.....">
<apex:actionFunction name="sayHello" action="{!load}" rerender="TheForm" status="mystatus"/>
<script>  sayHello(); </script>

Finally:
  1. Remove the action: <apex:page showHeader="false" action="{!load}" standardStylesheets="true" standardController="account" 
  2. Replace  <form> </form> with <apex:form ID="TheForm">  </apex:form> 
  3. Add the code below around : </apex:form>
		 <!-- Define the JavaScript function sayHello-->
         <apex:actionFunction name="sayHello" action="{!load}" rerender="TheForm" status="mystatus"/>
	</apex:form>
	<!--
		Call the sayHello JavaScript function using a script element
	-->
	<script>
	    sayHello();
    </script>
</apex:page>
That should work.

A simpler sample: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_actionFunction.htm

apex:actionFunction: A component that provides support for invoking controller action methods directly from JavaScript code using an AJAX request.  
Attribute: name String The name of the JavaScript function that, when invoked elsewhere in the page markup, causes the method specified by the action attribute to execute. When the action method completes, the components specified by the reRender attribute are refreshed.

Regards
Michele Kleinhomer 10Michele Kleinhomer 10
Thank you for the reply.  I have been learning VF on the fly and didn't know about adding JavaScript at the end to call a function.  That knowledge is going to really help me.  I added the code you suggested and now get a loading message before my data shows.  However, the form data was showing perfectly - a Skillset and then a list of Contacts under it.  Only the contacts related to the skill showed.  Now the Skill shows with the Contacts but blank lines for the contacts who are rendered false are showing.  Do you know why this would be the case.  When I call the Load action from the first line in VF this doesn't happen.  Thank you!  Below is a picture of what is displaying now (I changed the content) and my current VF page.User-added image
<apex:page showHeader="false" standardStylesheets="true" standardController="account" extensions="DisplayContactExpertise" sidebar="false" docType="html-5.0" applyBodyTag="False" applyHtmlTag="False">
<style type="text/css">
        body {
    background-color: white;
}
        .pbTitle {
        white-space:nowrap;
        border:white;
    }
    </style>
    <apex:form ID="TheForm">
           <apex:actionStatus id="mystatus" startText="Loading.....">
            <apex:facet name="stop">
            <apex:outputPanel id="out">
                </apex:outputPanel>
               </apex:facet>
                           </apex:actionStatus>

    
    <apex:repeat value="{!skills}" var="skill">
    <apex:pageBlock title="SkillSet" >
<apex:pageBlockSection columns="1" >
    
    
    <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px, 200px, 400px">
<apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}"> 
<apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink>
</apex:column>
    </apex:pageBlockTable>
</apex:pageBlockSection>
    </apex:pageBlock>
  </apex:repeat>
    	 <!-- Define the JavaScript function sayHello-->
         <apex:actionFunction name="sayHello" action="{!load}" reRender="TheForm"  status="mystatus"/>
	</apex:form>
	<!--
		Call the sayHello JavaScript function using a script element
	-->
	<script>
	    sayHello();
    </script>
</apex:page>
Michele Kleinhomer 10Michele Kleinhomer 10
Seeing this even when the column is manually rendered false.
User-added image
Alain CabonAlain Cabon
You have also changed the position of  </apex:actionStatus> and </apex:facet>. You were using a specific trick at the beginning.

<apex:actionStatus id="mystatus" startText="Loading.....">
     <apex:facet name="stop">  // return of the loading
          <apex:outputPanel id="out">
           ...
           // result when the loading is complete (return of {!load} here) : you complete VF page.
          ...
         </apex:outputPanel>
     </apex:facet>
 </apex:actionStatus>

If you move </apex:actionStatus> and </apex:facet>, you use another technique (perhaps more standard and simpler but that could not work as expected now)

Facets: stop  The components that display when an AJAX request completes. Use this facet as an alternative to the stopText attribute. Note that the order in which a stop facet appears in the body of an actionStatus component does not matter, because any facet with the attribute name="stop" controls the appearance of the actionStatus component when the request completes.

https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_actionStatus.htm
Michele Kleinhomer 10Michele Kleinhomer 10
I believe I made the changes you suggested.  I am still getting the blank rows.  It is as if the rendering isn't working when the form is rerendered.
 
<apex:page showHeader="false" standardStylesheets="true" standardController="account" extensions="DisplayContactExpertise" sidebar="false" docType="html-5.0" applyBodyTag="False" applyHtmlTag="False">
<style type="text/css">
        body {
    background-color: white;
}
        .pbTitle {
        white-space:nowrap;
        border:white;
    }
    </style>
    <apex:form ID="TheForm">
           <apex:actionStatus id="mystatus" startText="Loading.....">
            <apex:facet name="stop">
                <apex:outputPanel id="out">
            
    
    <apex:repeat value="{!skills}" var="skill">
    <apex:pageBlock title="SkillSet" >
<apex:pageBlockSection columns="1" >
    
    
    <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px, 200px, 400px">
<apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}"> 
<apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink>
</apex:column>
    </apex:pageBlockTable>
</apex:pageBlockSection>
    </apex:pageBlock>
  </apex:repeat>
                
                </apex:outputPanel>
               </apex:facet>
                           </apex:actionStatus>

    	 <!-- Define the JavaScript function sayHello-->
         <apex:actionFunction name="sayHello" action="{!load}" reRender="TheForm"  status="mystatus"/>
	</apex:form>
	<!--
		Call the sayHello JavaScript function using a script element
	-->
	<script>
	    sayHello();
    </script>
</apex:page>

 
Michele Kleinhomer 10Michele Kleinhomer 10
I should clarify that the rendering is somewhat working because I am only seeing the contacts related to the skill.  However, the blank lines are showing.
Alain CabonAlain Cabon
Without seeing the extension DisplayContactExpertise, I cannot help you. Sorry.
 
<apex:repeat value="{!skills}" var="skill">
    <apex:pageBlock title="SkillSet" >
   <apex:pageBlockSection columns="1" >
    <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px, 200px, 400px">
   <apex:column headerValue="Organization" rendered="{!IF(skill.NameSomething == contactskill.mkskill__r.name, true, false)}"> 
         <apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink>
    </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlockSection>
</apex:pageBlock>
</apex:repeat>

There is an error here: 

rendered="{!IF(skill.NameSomething == contactskill.mkskill__r.name, true, false)}">

or rendered="{!IF( NOT(ISBLANK(skill)) && skill == contactskill.mkskill__r.name, true, false)}">

Blind test.
Michele Kleinhomer 10Michele Kleinhomer 10
I am including my controller page.  Skills in this case is a string.
public with sharing class DisplayContactExpertise{
    public DisplayContactExpertise(ApexPages.StandardController controller) {
}



    public List<Skill_Contact_Relationship__c> contactskills {get;set;}  
    public String[] skills {get;set;}
    

  public void load() {

    
    contactskills = [Select id, mkskill__r.name, contact__r.name, contact__r.account.name, contact__r.email
                from Skill_Contact_Relationship__c 
                    
                 order by mkskill__r.name, contact__r.lastname];
      
    // dynamically create set of unique expertise from query
    Set<String> skillSet = new Set<String>();
      
    for (Skill_Contact_Relationship__c s : contactskills)
      skillSet.add(s.mkskill__r.name);

    // convert the set into a string array  
    skills = new String[skillSet.size()];
      
    Integer i = 0;
    for (String skill : skillSet) { 
      skills[i] = skill;
      i++;
    }

  }

}

 
Alain CabonAlain Cabon
  1. Apex: if (s.mkskill__r.name != null) { .. }
  2. VFP:  <apex:outputText value="{!contactskill.mkskill__r.name}"></apex:outputText>
 
public with sharing class DisplayContactExpertise{
  public DisplayContactExpertise(ApexPages.StandardController controller) {
  }
  public List<Skill_Contact_Relationship__c> contactskills {get;set;}  
  public String[] skills {get;set;}
  public void load() {
    contactskills = [Select id, mkskill__r.name, contact__r.name, contact__r.account.name, contact__r.email
                from Skill_Contact_Relationship__c 
                order by mkskill__r.name, contact__r.lastname];
    // dynamically create set of unique expertise from query
    Set<String> skillSet = new Set<String>();   
    for (Skill_Contact_Relationship__c s : contactskills) {
      if (s.mkskill__r.name != null)  {
           skillSet.add(s.mkskill__r.name);
      }      
    }
    // convert the set into a string array  
     skills = new String[skillSet.size()];      
     Integer i = 0;
     for (String skill : skillSet) { 
        skills[i] = skill;
        i++;
     }
   }
}

For the test:
<apex:repeat value="{!skills}" var="skill">
    <apex:pageBlock title="SkillSet" >
   <apex:pageBlockSection columns="1" >
    <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px, 200px, 400px">
   <apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}"> 
          <apex:outputText value="{!contactskill.mkskill__r.name}"></apex:outputText>
          <!-- apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink -->
    </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlockSection>
</apex:pageBlock>
</apex:repeat>

The trick used with <apex:facet> should work but there could be a difference of behavior for instance at the level of <apex:page> and its previous action.
 
Alain CabonAlain Cabon
You can also filter the SOQL request  instead of  if (s.mkskill__r.name != null) { .. }
 
contactskills = [Select id, mkskill__r.name, contact__r.name, contact__r.account.name, contact__r.email from Skill_Contact_Relationship__c where mkskill__r.name != null   order by mkskill__r.name, contact__r.lastname];
 
Michele Kleinhomer 10Michele Kleinhomer 10
I really appreciate you looking into this. I don't think I need the if conditional in my apex because I am retrieving the data from a junction table that only contains applicable records. It joins a skills/expertise object with the Contacts object. The junction object contains records with a field pointing to the appropriate Contact and a field pointing to the appropriate skills.
Michele Kleinhomer 10Michele Kleinhomer 10
If I am thinking of everything correctly, I will never have a record in Skill_Contact_Relationship where mkskills__r.name is Null. Please correct me if I am mistaken (very likely).
Alain CabonAlain Cabon
By the way, if you want to have only one record for each mkskill__r.name in the page , you will not have this result with your apex code and current VFP. 
Michele Kleinhomer 10Michele Kleinhomer 10
I am able to get the page to work correctly without the Loading... text we have been workinig to add. Without the "Loading..." text, I nicely get: Skill 1 Contact 1 Contact 2 Contact 3 Skill 2 Contact 4 Contact 5 Contact ...
Michele Kleinhomer 10Michele Kleinhomer 10
I have a many to many relationship going with this. Each contact can have multiple skills and each skill can have multiple contacts.
Alain CabonAlain Cabon
"I will never have a record in Skill_Contact_Relationship where mkskills__r.name is Null." : I don't know.

Try the following request and post the result (that must be a number): 

Select count(id)
from Skill_Contact_Relationship__c 
where mkskill__r.name != nul​

 <apex:repeat value="{!skills}" var="skill"> : Seeing this even when the column is manually rendered false. 
 
Michele Kleinhomer 10Michele Kleinhomer 10
I am validly seeing the Skill name all the time. The problem is that I am seeing blank rows under the Skill name when the rendered false setting is set in the column. The rows should be hidden when the column display setting is rendered false. This does happen when I don't use Javascript to rerender the form. Do you still want me to do the Count on blank records on the junction table? Michele
Alain CabonAlain Cabon
and the folowing request :

Select count(id)
from Skill_Contact_Relationship__c 
where mkskill__r.name = nul​

https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_null.htm

Please post the result (that must be also a number)
Michele Kleinhomer 10Michele Kleinhomer 10
Can you tell me what I am doing wrong when attempting to do the test you mentioned. I am getting an error that a list cannot go to an integer variable. It doesn't like when I make try to assign the result to a list either. public List contactskills {get;set;} public List Testcontactskills {get;set;} public String[] skills {get;set;} public float nullCount; public void load() { nullCount = [Select count(id) from Skill_Contact_Relationship__c where mkskill__r.name = null]; contactskills = [Select id, mkskill__r.name, contact__r.name, contact__r.account.name, contact__r.email from Skill_Contact_Relationship__c
Alain CabonAlain Cabon
The problem is also your two loops. One loop should be sufficient.
<apex:pageBlock title="SkillSet" >
   <apex:pageBlockSection columns="1" >
    <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px, 200px, 400px">
   <apex:column headerValue="Organization"> 
          <apex:outputText value="name={!contactskill.mkskill__r.name}"></apex:outputText>
          <!-- apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink -->
    </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlockSection>
</apex:pageBlock>

What do you see now?
Michele Kleinhomer 10Michele Kleinhomer 10
I added your code.  I get the Skill page block header & then all of the junction records listed under each skill.  When I add the render false logic, I get the correct items displaying but I have the blank rows.
<apex:page showHeader="false" standardStylesheets="true" standardController="account" extensions="DisplayContactExpertise" sidebar="false" docType="html-5.0" applyBodyTag="False" applyHtmlTag="False">
    <style type="text/css">
            body {
        background-color: white;
    }
            .pbTitle {
            white-space:nowrap;
            border:white;
        }
        </style>
        <apex:form ID="TheForm">
               <apex:actionStatus id="mystatus" startText="Loading.....">
                <apex:facet name="stop">
                    <apex:outputPanel id="out">
                
        
        <apex:repeat value="{!skills}" var="skill">
  <apex:pageBlock title="{!skill}">
   <apex:pageBlockSection columns="1" >
    <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px, 200px, 400px">
   <apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}"> 
          <apex:outputText value="name={!contactskill.mkskill__r.name}"></apex:outputText>
          <!-- apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink -->
    </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlockSection>
</apex:pageBlock>
      </apex:repeat>
                    
                    </apex:outputPanel>
                   </apex:facet>
                               </apex:actionStatus>
    
             <!-- Define the JavaScript function sayHello-->
             <apex:actionFunction name="sayHello" action="{!load}" reRender="TheForm"  status="mystatus"/>
        </apex:form>
        <!--
            Call the sayHello JavaScript function using a script element
        -->
        <script>
            sayHello();
        </script>
    </apex:page>

User-added image
Alain CabonAlain Cabon
 <apex:pageBlockTable> is already a loop.

You don't need <apex:repeat>

Sorry, I forgot to tell you about the current loops.

<apex:repeat value="{!skills}" var="skill">
<apex:pageBlock title="{!skill}">
  <apex:pageBlockSection columns="1" >
   <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill"columnsWidth="200px, 200px, 400px">
  <apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}">
          <apex:outputText value="name={!contactskill.mkskill__r.name}"></apex:outputText>
         <!-- apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink -->
       </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlockSection>
</apex:pageBlock>
</apex:repeat>

You are using two loops and that is useless.

https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_pageBlockTable.htm
 
Michele Kleinhomer 10Michele Kleinhomer 10

I tried the code you provided.  With what you provided, I no longer have the skills grouping visual display and I am still seeing blank rows.  Below is my code & picture of the results.

<apex:page showHeader="false" standardStylesheets="true" standardController="account" extensions="DisplayContactExpertise" sidebar="false" docType="html-5.0" applyBodyTag="False" applyHtmlTag="False">
    <style type="text/css">
            body {
        background-color: white;
    }
            .pbTitle {
            white-space:nowrap;
            border:white;
        }
        </style>
        <apex:form ID="TheForm">
               <apex:actionStatus id="mystatus" startText="Loading.....">
                <apex:facet name="stop">
                    <apex:outputPanel id="out">
                
        
        <apex:repeat value="{!skills}" var="skill">
  <apex:pageBlock >
   <apex:pageBlockSection columns="1" >
   <apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill" columnsWidth="200px">
  <apex:column headerValue="Organization" rendered="{!IF(skill == contactskill.mkskill__r.name, true, false)}">
          <apex:outputText value="name={!contactskill.mkskill__r.name}"></apex:outputText>
         <!-- apex:outputLink style="text-decoration:none">DifferentContactNames</apex:outputLink -->
       </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlockSection>
</apex:pageBlock>
  
      </apex:repeat>
                    
                    </apex:outputPanel>
                   </apex:facet>
                               </apex:actionStatus>
    
             <!-- Define the JavaScript function sayHello-->
             <apex:actionFunction name="sayHello" action="{!load}" reRender="TheForm"  status="mystatus"/>
        </apex:form>
        <!--
            Call the sayHello JavaScript function using a script element
        -->
        <script>
            sayHello();
        </script>
    </apex:page>

User-added image
Alain CabonAlain Cabon
Hello,

You don't need: <apex:repeat value="{!skills}" var="skill"> (must be deleted)
You are using two loops and only one loop is sufficient.

<apex:repeat value="{!skills}" var="skill">
<apex:pageBlockTable align="center" border="3" value="{!contactskills}" var="contactskill"columnsWidth="200px">

... and the code in the apex class; must be rewritten entirely according to me.

All your apex code seems wrong. You can open a new question explaining your problem from the beginning (here and on other forums with your strange result with your code, there is not much chance that somebody else helps you but you can try  https://salesforce.stackexchange.com/   you can get an answer that day).

If you don't have the extra blanks lines without the trick of the javascript function, remove it and that will work fine. 

Regards
Michele Kleinhomer 10Michele Kleinhomer 10
I appreciate your help. I am new to Apex and have been piecing together code that I find online. It does work without the call to the Javascript. However, I am looking to improve. The bottom line is that I am dealing with three objects - Contacts, Skills, and a junction table. I want to display the data such that it appears as it would in a grouped by report. Currently, I retrieve the records from the junction object and put them in an arraylist. I then take that list and pickout the skills and put them in a string. VF loops through the string and in the table displays records whose skill is equal to the string element that we are on. Can you suggest a different way to accomplish this? Thank you, Michele
Michele Kleinhomer 10Michele Kleinhomer 10
I will post a new question to the groups you mentioned.
Alain CabonAlain Cabon
You should post the strange result with your question (for me, the problem is the main useless loop, it is logical but the trick with the javascript call is perhaps the main problem, worked in some cases but not for your code apex which should be rewriten).
People are interested by strange results if they can see it directly in the question.

You wrote: "Below is the code I have that works but is slow loading." and there is the javascript call (?)

https://salesforce.stackexchange.com/questions/195787/salesforce-code-advice-for-displaying-records-in-a-grouped-by-format

No one will respond if you say that works yet.
Michele Kleinhomer 10Michele Kleinhomer 10
I decided to abandon showing a Loading message & am denormalizing my data to improve performance. I think this is a better solution anyway.
Alain CabonAlain Cabon
Ok, you have finally rewrite your apex code as I would have expected.

This tricky solution is not stable for the loading of the initial page in your case.

We often use the loading message from a button on the loaded page but for the initial loading, the result seems not stable. 

No one responds to your initial question on salesforce.stackexchange.com but you should put a question more simple: how to show a Loading message with an action="{!load}" even if you will get the "eltoro" solution probably again (but not sure).

All the standard pages in Lightning have a  loading spinner right now (standard behavior) but that doesn't exist in Classic.
There is surely a reason (insufficient stability?)
Michele Kleinhomer 10Michele Kleinhomer 10
I am also looking to see if I can switch to using multi-select picklist instead of the junction table solution.