3

I have a grid Visualforce component that displays records as rows where fields are editable as apex:inputField. The component works for generic SObjects and uses fieldsets to defined editable fields.

In one usage each record has two dependent Lookup fields, where one defines a Filter on the other.

The problem is one of the fields is not rendered correctly (gray background to show dependency) and the other has a Lookup button that produces a JS error in a Salesforce-internal class main.js.

enter image description here

I could boil the problem down to see where the root cause is. The problem is passing the apex:inputField value attribute an SObject wrapped in a Wrapper object and using the generic map-method to access the field.

<apex:component controller="ComponentCtrl" allowDML="true"> 
    <apex:attribute name="originalRecords" type="SObject[]" assignTo="{!recordList}" required="true" description=""  />

   {!getInit} <!-- Pseudo Constructor -->

    <apex:pageBlock >
        <h1>No wrapper class and it works!</h1>

        <apex:pageBlockTable value="{!originalRecords}" var="originalRecord">
            <apex:column >
                <apex:inputField value="{!originalRecord['LookupField1__c']}" />
                <apex:inputField value="{!originalRecord['LookupField2__c']}" />     
          </apex:column>
       </apex:pageBlockTable>

        <h1>With wrapper class and it FAILS!</h1>

        <apex:pageBlockTable value="{!wrappedRecords}" var="wrapper">
            <apex:column >
                <apex:inputField value="{!wrapper.record['LookupField1__c']}" />
                <apex:inputField value="{!wrapper.record['LookupField2__c']}" />     
          </apex:column>
        </apex:pageBlockTable>

    </apex:pageBlock>

</apex:component>

I think this problem might be connected to this Known Issue: Lookup Filter doesn't allow lookup window to open due to javascript error on order product multi-line edit page

  • 1
    Does your page or component include any JavaScript that could break the standard Salesforce JavaScript? – Keith C Dec 5 '14 at 11:31
  • Both component and embedding page contain Javascript. But I have ne clue how to assess if they are risky to overwrite standard scripts. – Robert Sösemann Dec 5 '14 at 13:26
  • 1
    I'd start by commenting them all out and see if the JavaScript error goes away. If it does go away, add bits back in until it breaks again to at least narrow down the search. – Keith C Dec 5 '14 at 14:55
  • @KeithC: I removed all the JS involved in the page and the component and the problem still exists. What I found out is that only the last occurrence of this field fails to render and work. See the changed screenshot above. When I display in my table another record of the same type its filtered lookup is perfectly rendered fine and the button works. Can this be a bug in the length function of the SFDC JS??? – Robert Sösemann Dec 9 '14 at 11:29
  • 1
    It would be a good thing if it is as bugs only make it to that list of they are going to be fixed AFAIK. – Keith C Dec 11 '14 at 11:11
1

After weeks I got a solution by Salesforce.com Support stating that this is NOT a bug but an "order of execution" problem. And indeed there solution fixed it:

According to the current code:

  • The dependent data for filter lookup is generated in Step 2, which is "Evaluate constructors on Controllers, extensions, and expressions on attribute definitions."
  • The "{!init}" expression is evaluated in Step 3, which is "Evaluate expressions, action attribute, and other method calls."

  • So, in this scenario, the dependent data for filter lookup is generated even before the {!init} expression is evaluated, which results in the issue being faced.

In order to make this work correctly I change my Component Controller code (simplified) from:

public with sharing class SFDCComponentCtrl { 
  public List recordList { get; set; } 
  public List rows { get; private set; } 

  public void getInit() { 
    rows = new List(); 

    for(SObject record : recordList) { 
    rows.add( new SObjectRow(record) ); 
    } 
  } 


  public with sharing class SObjectRow { 
    public SObject record { get; set; } 

    public SObjectRow(SObject record) { 
      this.record = record; 
    } 
  } 

}

to

public with sharing class SFDCComponentCtrl { 
  public List recordList { get; set { recordList = value; getInit(); } } // CHANGED
  public List rows { get; private set; } 

  public void getInit() { 
    rows = new List(); 

    for(SObject record : recordList) { 
    rows.add( new SObjectRow(record) ); 
    } 
  } 


  public with sharing class SObjectRow { 
    public SObject record { get; set; } 

    public SObjectRow(SObject record) { 
      this.record = record; 
    } 
  } 

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.