0

I have a visualforce component that displays parts of a record named "tvCase__c". This record may be updated from another component or outside, but the component should always display the most recent status, but the panel should only refresh the displaying outputPanel, IF the record really changed.

So I created a apex:actionPoller, calling a controller method that checks if an update happend and sets a boolean accordingly. This boolean is checked in the rerender attribute. But no matter what I do, it keeps on refreshing the "outerPanel".

Here's the part of the component

<apex:form id="form">
    <apex:outputPanel id="emptyPanel" >
      <apex:actionPoller action="{!checkCaseDetailsForUpdates}" rerender="{!IF(tvCaseDetailsHaveBeenUpdated, 'outerPanel', 'emptyPanel')}" interval="5" />
        EmptyPanel: {!NOW()} {!tvCaseDetailsHaveBeenUpdated} <br/>
    </apex:outputPanel>
    <apex:outputPanel id="outerPanel">
    OuterPanel: {!NOW()} {!tvCaseDetailsHaveBeenUpdated} <br/>
    <apex:outputPanel id="classicView" rendered="{!$User.UIThemeDisplayed = 'Theme3'}">
        <apex:pageBlock mode="maindetail" rendered="{! IF(pageView !='share',true,false)}">
            <div class="classicDetailList">           
              <apex:pageBlockSection columns="2" >
                <apex:outputField value="{!serviceCase.tvCustomerLink__c}"/>
                <apex:outputField value="{!serviceCase.tvExpirationDate__c}"/>
                <apex:outputField id="tvcaseId" value="{!serviceCase.tvCaseId__c}"/>
                <apex:outputField value="{!serviceCase.tvSupportLink__c}"/>              
              </apex:pageBlockSection>
            </div>  
        </apex:pageBlock>
    </apex:outputPanel>
    </apex:outputPanel>
</apex:form>

I had the actionPoller inside and outside the Panels that need reload. The checkCaseDetailsForUpdates has the correct / expected value. Here's the method:

// the case itself might change from outside the component
public void checkCaseDetailsForUpdates(){
    tvCase__c serviceCaseToCheck = new tvCase__c();
    List<tvCase__c> serviceCaseList = new List<tvCase__c>();

    serviceCaseList = [Select id, parentId__c, tvCustomerLink__c, tvCaseId__c, LastModifiedDate, 
    tvExpirationDate__c, tvSupportLink__c FROM tvCase__c WHERE parentId__c = : sObjectId LIMIT 1];
    tvCaseDetailsHaveBeenUpdated = false;
    if(serviceCaseList!=null && !serviceCaseList.isEmpty()) {
        serviceCaseToCheck = serviceCaseList.get(0);
    }
    if(serviceCaseToCheck == null && this.ServiceCase != null){
        tvCaseDetailsHaveBeenUpdated = true;
    }
    if(serviceCaseToCheck.LastModifiedDate > this.serviceCase.LastModifiedDate){
        tvCaseDetailsHaveBeenUpdated = true;
    }

    if(tvCaseDetailsHaveBeenUpdated){
        this.serviceCase = serviceCaseToCheck;
    }
}

I can't figure it out. Ideas, anyone?

1 Answer 1

0

You need to not initialize the local variables (or at least, not twice):

tvCase__c serviceCaseToCheck; // = new tvCase__c();
List<tvCase__c> serviceCaseList; // = new List<tvCase__c>();

Results of a query are never null.

if(/*serviceCaseList!=null && */ !serviceCaseList.isEmpty()) {
    serviceCaseToCheck = serviceCaseList[0]; // (instead of .get(0))
}

We need to make sure that serviceCase and serviceCaseToCheck are both not null to avoid errors.

if((serviceCaseToCheck == null && this.ServiceCase != null) || serviceCaseToCheck.LastModifiedDate > this.serviceCase.LastModifiedDate) {
    tvCaseDetailsHaveBeenUpdated = true;
}

So we can remove these three lines:

/* Null Pointer Exception avoided here, by moving criteria up to the previous condition...
if(serviceCaseToCheck.LastModifiedDate > this.serviceCase.LastModifiedDate){
    tvCaseDetailsHaveBeenUpdated = true;
}
*/

However, in the end... you can't reliably use dynamic ID values this way.

  • Rerender cannot be a dynamic value, meaning that EVEN IF you statically put the visualforce rendered ID (i.e. j_id0:j_id38), it will not rerender

  • Rerender cannot be bound to a controller instance variable. Along the lines of the previous statement, besides the trickyness of dynamically binding a component ID to a variable, even if you do it would not rerender

Go look at that question/answer, there's a slightly complicated workaround, and perhaps you could get more complicated by signalling a JavaScript method that would do a "double-rerender" to update only the affected area.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .