• 1542VeMan
  • NEWBIE
  • 10 Points
  • Member since 2013

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 9
    Questions
  • 8
    Replies
Most of the examples of generating dynamic pickist options assumes that there is a known inputSelect component to which to add them. However, when creating components from fieldsets, one has to determine in realtime that a field in the set is a picklist. Then we have to create that inputSelect dynamically, and then create the inputSelectOptions after generating the inputSelect component, then add the entire bundle to a dynamic form component. 

The component containing all of this looks ike this:
<aura:component controller="ltngController">
    <aura:attribute name="userId" type="String" /><!--used to find the Contact-->
    <aura:attribute name="contact" type="Contact"/>
    <aura:attribute name="fieldSetName" type="String"/>
    <aura:attribute name="fields" type="Object[]"/><!--custom FieldSetMember class-->
    <aura:attribute name="picklistValues" type="Object[]" /><!--custom picklistOptions class-->
    <aura:attribute name="form" type="Aura.Component[]"/><!--dynamic component where generated components will be placed-->

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <!--HTML and other Lightning components-->

    <div class="row">
            <div class="section">
                <div class="cell form">
                          {!v.form}   
                </div>
            </div>
        </div>
</aura:component
The JSController runs the doInit which calls the server and gets the fieldSet data. This data is moved into a custom FieldSetMember class whose properties are AuraEnabled. For picklists, a describe call gets the Picklist value for this field and stores them in a list of custom PicklistValues objects. All this and the Contact record is bundled into a wrapper object and sent back to the JSController callback method. 
Checking the Debug Log and the Chrome Inspector verifies that all the data is available in the component controller, so that's not the problem.

Next step is to dynamcially create the components to hold the fieldSetdata in a helper method called 'createForm'. When a picklist value is encountered, I run the following 
createForm : function(cmp) {
	var fields = cmp.get('v.fields');
        var obj = cmp.get('v.contact');
        for (var i = 0; i < fields.length; i++) {
            var field = fields[i];
            if (field.type == 'PICKLIST'){
                var picklistValues = cmp.get("v.picklistValues");//all values for all picklist fields
                $A.createComponent("ui:inputSelect",
                                              {"label":field.label,
                                               "aura:id":field.label,
                                               "value":obj[field.fieldName],
                                               "required":field.required},
                    function(newSelect){
                        if (newSelect.isValid()){ // loop through the values to create options
                            for (var i = 0; i < picklistValues.length; i++){
                                var pItem = picklistValues[i];
                                
                                if (pItem.fieldName == field.fieldPath){ //only create for values that 
                                                                         //match the field's options
                                    $A.createComponent("ui:inputSelectOption",
                                                                  {"label":pItem.ItemLabel,
                                                                   "text":pItem.ItemValue},
                                          function(newOption){
                                              if (obj[field.fieldName] == pItem.ItemValue)
                                                  newOption.set("v.value":true);
                                                         
                                                   // get the inputSelect component's options attribute
                                                  var options = newSelect.get("v.options");
                                                  options.push(newOption);
                                                  newSelect.set("v.options",options);
                                          });
                                }
                            }
                        }
                        // after all picklist options are created and pushed into the v.options 
                        // attribute of the created inputSelect component, it all gets pushed into 
                        // the main component's v.form.
                           var form = cmp.get("v.form");
                           form.push(newSelect);
                           cmp.set("v.form",form);
                    });
            }
        }
}

OK, so after checking with the debugger; statement, all of those components appear to be created correctly. However, when I run the process, the picklist fields appear, with the correct label, but the drop-down for each reveals no selectOptions, even though there is enough empty space in the dropdown to match the number of options that should be visible. Here is a screen show of the rendered page:

User-added image
Agai, looking at the inputSelectOptions using the debugger statement in the Chrome DevTools Inspector showed that even as they were being inserted into the inputSelect component's options list, they contained the expected data, and the inputSelect components are showing in the form tag alongside the other field types. 

But WHY do the values not appear????? Any help is appreciated

I have a situation where an update to an object (objA) finds a Child Obj (objB), then updates a grandchild object (objC) related to the child. 

So far the Flow is completing all the steps, according to the debug log, but the grandchild object is failing to update. 

The process start from an invocable process in the process builder that launches the flow providing three variables, including the objA Id. The Flow is then launched with a DecisionStep:
DECISION - checkObjAId - checks if the varObjAId variable is not null. The Yes decision leads to a record lookup step for the child objB record

RECORD LOOKUP - FindObjB - Lookup objB where objA_lookup = varObjAId, 
                                   Action: assign objBId to varObjBId variable
Next I have another decision step to eusure the varObjBId value has a value

DECISION - checkObjBId - checks if the varObjBId is not null. The Yes decision leads to a Record Update step for the grandchildObjC record

RECORD UPDATE - updateObjC - Lookup objC where objB_Lookup = varObjBId
                                  Action: update objC field values with the other two variables provided to the flow from the ProcessBuilder. 
This step does fire, according to the debug log, but refreshing the objC record in Salesforce does not reflect the updated values.

Am I missing something obvious? I can add screen shots of each step i nthe Flow if it helps, but all the steps are firing according to the log. 

I created a Record Type on a Custom object and assigned it to all profiles. That means it became the default Record Type for that object on Custom and Standard Profiles. 

Now when trying to change the default record type back to Master on the Service Cloud profile, I get an error:

Permission Modify All Data depends on permission(s): Create and Set Up Communities
Permission Download AppExchange Packages depends on permission(s): Create and Set Up Communities
Permission Author Apex depends on permission(s): Create and Set Up Communities

I would love to just add the Create and Set up Communities on the Service Cloud Profile, but there is no way to edit it, since its standard and thus there is no way to change the default record type back to Master since it won't save until that permission is added. . Never mind that I don't have Communities enabled in the first place. In future, I'll be more vigilant not to assign Record Types for anything to standard profiles, but this seems like a glitch.

Anyone know how to either bypass this headache so I can finally delete the unnecessary record type?

I am basically diving into Lightning Component Development as I generally learn faster applying examples to real-world problems. In this case, I am trying to replace a javascript button that launched a window with a Visualforce page that has its own styling, Unfortunately adding the launch as a quickAction will open the window, but I can't get the size to match the content, making it largely unusable, even with scroll bars. 

Instead, I figure since Lightning Components are so Javascript heavy anyway, why can't I just build a Lightning Component featuring a UI button, an APEX controller providing a method to return the record ID, and a js controller with a doInit()function that queries the record data, while the button click launches the newInterview() method which contains the original Javascript that opens the Visualforce page using the parameters from the current record. That's the idea anyway...

Here is how I tried to build it:

COMPONENT
<aura:component controller="AuraMethods" implements="flexipage:availableForAllPageTypes,force:lightningQuickAction,force:hasRecordId" access="global" >
	<aura:attribute name="opp" type="Opportunity"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <ui:button label="New Interview" press="{!c.newInterview}"/>
</aura:component>

JS CONTROLLER
({
	doInit : function(component, event) {
		var action = component.get(c.findOppById("v.recordId"));
        action.setCallback(this, function(a) {
            component.set("v.opp", a.getReturnValue());
        });
        $A.enqueueAction(action);
	}
})

({
    newInterview : function(component, event){
        if(component.get("v.opp.School_Interview_Type__c")== '3W' || component.get("v.opp.School_Interview_Type__c") == '3W+School'){ 
        	window.location.href = "/apex/AM_Time_Slots2?id="+component.get("v.opp.Id")+"&Name="+component.get("v.opp.Name"); 
        } 
        else{ 
        	alert('please do not make an appointment AM time when the School Interview Type not equals 3W,only need to confirm the following AM given in the school time.'); 
        }
    }  
})

APEX CONTROLLER
public with sharing class AuraMethods {
    @AuraEnabled
    public static Opportunity findOppByID(String OppId){
        return [Select id, Name, School_Interview_Type__c from Opportunity where Id = :OppId];
    }
}


That's pretty much it. The Component appears in the Custom Components section of my Lightning Page Layout for the Opportunity in the App Builder, but when I try to place it I get the following error:

'Action failed: c:InterviewScheduling$controller$doInit [c is not defined] doInit()@components/c/InterviewScheduling.js:10:30'

I know I'm still a bit green to JS, as well so I may have missed something. More important, I've seen several posts about the difficulty of getting a javascript button's functionality to work in Lightning. I really just want to be able to launch this Visualforce page from within the Opportunity and have it appear in all its glory rather than in some dinky popup window where I can't adjust the width in the settings. 

I appreciate all responses. Kindness and patience is appreciated. I will learn this. 

Thanks!

V

I have a setController where I'm using a database.queryLocator entering a query string that ends with a LIMIT clause under 10000. 

When I set the LIMIT clause in the query string, the setCon.getCompleteResult() method reports as TRUE - that is all the records were found. The problem is that we have over 10000 records of this object, so I would expect the setController response to be FALSE. 

If I remove the LIMIT clause in the query string, the system returns a too many rows error. 

I don't see any examples on the board, in the documentation, or anywhere else where the getCompleteResult() method on the setController is used in a situation where there are too many records in the database, so I don't see when the getCompleteresult() method would ever return a value of FALSE. If you add a LIMIT clause to the query, getCompleteResult() says I got all the records, which I know isn't true. If I don't, I get the query error. 
 

// this is supposed to tell the user that the result is incomplete and to apply a filter
public boolean resultComplete {get; set;}

public ApexPages.StandardSetController SetCon {
        get {
            if(SetCon == null) {
                System.debug('SetCon is null; loading');
                String query = getQuery();   //returns query string ending with 'LIMIT 5000'
                SetCon = new ApexPages.StandardSetController(Database.getQueryLocator(query));
            }
            setCon.setPageSize(pageSize);

            numAvailableLogs = setCon.getResultSize(); // this = 5000
            System.debug('numAvailableLogs is '+numAvailableLogs);

            numPages = (math.mod(numAvailableLogs,pageSize) == 0)? (numAvailableLogs/pageSize) : ((numAvailableLogs/pageSize)+1); 

            resultComplete = setCon.getCompleteResult(); // this returns true (there are more records)
            System.debug('setCon resultComplete is '+resultComplete);

            hasNext = setCon.getHasNext();
            hasPrevious = setCon.getHasPrevious();
            pageNumber = setCon.getPageNumber();
            return SetCon;
        }
        set;
    }

 
I've embedded a VF page using a setController into a detail page layout. I'm using the standard pagination functions and have added the same VF code for the next, previous, first, last commands into the top and bottom of the pageBlock containing the table. 

These are showing up at the top, but for some reason they don't show up on the bottom. Yes, I've added both the scrolling functions, as well as increased the size of the page section to fit the entire table. Doesn't matter. 

I've created the same VF page as itws own Tab, and the page functions show up at the top and bottom, so the code is right. I'm thinking that there is something about the embedded VF page in a page layout that is preventing the pagination functions from appearing. 

Anyone else had this problem??

Thanks to all!

V

Our application logs the user into and opens a website in an iFrame in a Visualforce page. Our problem is that when the user leaves the iFrame page using a back button, or when closing the browser, he is still logged in to the external site. 

I'm attempting to use cascading actionFunctions, where the last one fires oncomplete of the first. 
 

<apex:page controller="iFramePageController" sidebar="false" >
   
    <apex:form >
        <apex:actionFunction action="{!logoutOfApp}" name="logoutOfApp" immediate="true" reRender="iFrame" oncomplete="return()">
            <apex:param assignTo="{!logout}" name="logoutSwitch" value="true"/>
        </apex:actionFunction>
        
         <apex:actionFunction action="{!Back}" name="return" />
       
         <apex:commandButton value="Back"  onclick="logoutOfApp()" />
       
    </apex:form>
    
    <apex:iframe src="{!iFrameUrl}" id="iFrame"/>
    
</apex:page>


Controller:
public class iFramePageController {
       
    private string retUrl;
    private string logoutURL = 'https://AppCompany.com/logout.jsp?submitOK=true';
    
    public PageReference Back() {
        
        return new pageReference(retURL).setRedirect(true);
    }

    public pageReference logoutOfApp(){
        return new PageReference(logoutURL);
    }

    public String getiFrameUrl() {
         if (logout)
              return logoutURL;
         else{
              ... lots of login code that initiates the iFrame
         }
    }


}
Clicking the Back button will call the logoutOfApp action function, which passes the true parameter to a boolean value, then refreshes the iFrame.

the getiFrameURL should now provide the logoutURL (since logout is now 'true') to the src value in the iFrame tag

Once the rerender is complete, I expected the 2nd function to be called Back(), which uses the retURL initially provided to the page to redirect the user back to that page. 

Currently this isn't working and the page basically refreshes with the iFrame intact. I was able to sucessfully call the logout function when using the onmouseover in the Back button, but it never made it to redirecting to the return page. 

The thought was that I could refresh the iFrame to the logout page, thus logging out the user, then get the user back to the original page ensuring that the user was truly logged out. 

Not sure why this isn't working. Any help much appreciated to get it working, or help kme understand why it either doesn't or cannot work would be appreciated. 

Thanks

VeMan


 
I am using a wrapper class to combine an sObject with a checkbox, then iterating over the wrappers in my list. The first column displays the checkbox, then a repeat tag iterates over a list of strings derived from the object fieldNames, allowing the table to render columns according to the object's fieldSet.

the 'fieldSetList' is a list of field Names and I'm using a dynamic APEX process so that the client can reconfigure their table by changing the value and their order in the field set on the custom object.

The table displays correctly, however I want to be able to sort the table by clicking on the column. To do this, I have tried to add an onclick call to an ActionFunction ('sortCLTable') to the column and sending the repeat tag's interation variable ('f') as a parameter: 'onclick="sortCLTable(f)"'

The ActionFunction's parameter should set the sortValue property in the controller, and run the sorttable method, but alas it does not. The table columns have no response whatsoever.
 
​<apex:page ...> 
<apex:form> 
   <apex:outputPanel id="thePanel">
       <apex:pageBlockTable value="{!CLWraps}" var="CLWrap"> 
             <apex:column headervalue="Select" > 
                  <apex:inputCheckbox value="{!CLWrap.selectbox}"/> 
             </apex:column> 
             
             <apex:repeat value="{!fieldSetList}" var="f" > 
                  <apex:column value="{!CWrap.CL[f]}" onclick="sortCLTable(f)"/> 
                     // I've also tried sortTable('f'), sortCLTable({!f}) and sortTable('{!f}')
             </apex:repeat> 

        </apex:pageBlockTable> 
    </apex:outputPanel> 
    
    <apex:actionFunction action="{!sortTable}" name="sortCLTable" reRender="thePanel">          
          <apex:param name="firstParam" assignTo="{!sortValue}" value="" /> 
    </apex:actionFunction> 
  </apex:form> 
</apex:page>

CONTROLLER contains:

public string sortValue {get; set;} 
public pageReference sortTable(){ 
    resetQueryWithSortValue(sortValue); 
    return null; 
}

Although the 'f' is working to set the column header and reference the correct field value. it doesn't appear to be passing through the onclick call as a parameter to the apex:Param value associated with the function, or to the controller's corresponding 'sortValue' property. I think I've written the page tags correctly...

Using ActionSupport instead appears to mess up the repeat function such that the column names no longer appear - not sure why. Neither do the columns sort. 

I can add more code from my example if needed, but figured this would describe the problem. Any help is much appreciated.

Thanks

This is probably an easy solution, but its really frustrating:

 

The page is using a selectList to provide a value to the query in the controller. The query results should be displayed in a pageBlockTable, but the table isn't rendering when the commandButton is pushed. 

 

I'm pretty sure the select value is being set, and the query is firing as expected, but I can't figure out ahy the table isn't rendering: Here is the code:

 

public with sharing class CompController {

  public list<string> compNames {get; set;}
  public list<Comp__c> comps;
  public list<SelectOption> compList;
  public id selectedComp {get; set;}
  
  public CompController() {
    comps = new list<Comp__c>([select id, Name from Comp__c]);
    compList = getCompList();
  }
  
  public list<SelectOption> getCompList() {
    compNames = new list<string>();
    compList = new list<SelectOption>();
    for (Comp__c Comp :comps) {
    	system.debug(Comp.Name);
        compNames.add(Comp.Name);
        compList.add(new SelectOption(Comp.id, Comp.Name));
    }
    return compList;
  }
  
  public list<Comp_Control__c> Controls;
  
  public list<Comp_Control__c> getControls() {
  	return Controls;
  }
  
  public list<Comp_Control__c> setControls(id CID){
    Controls = new list<Comp_Control__c> ([select id, Control__c, Control_Category__c, 
Control_Number__c
from Comp_Control__c where Comp__c = :CID]);
return Controls; } public pageReference fetchControls() { setControls(selectedComp); return null; } }

 

The page is here:

<apex:page controller="ComplianceController">
  <apex:form >
    <apex:pageBlock title="Compliance Control Check">
      Select Compliance <p/>
      <apex:SelectList value="{!selectedComp}" >
        <apex:SelectOptions value="{!CompList}"/>
      </apex:SelectList>
      <apex:commandButton value="Fetch Controls" 
                          action="{!fetchControls}" reRender="CompControls"/>
      <p/><p/>
      <apex:outputPanel id="CompControls">
          
        <apex:pageBlockTable value="{!Controls}" var="C">
          <apex:column >
            <apex:outputLink value="/{!C.Control__c}">{!C.Control__r.Name}
            </apex:outputLink>
          </apex:column>
          <apex:column value="{!C.Control_Number__c}"/>
          <apex:column value="{!C.Control_Category__c}"/>
        </apex:pageBlockTable>
          
      </apex:outputPanel>
    </apex:pageBlock>
  </apex:form>
</apex:page>

 Any feedback is appreciated

Most of the examples of generating dynamic pickist options assumes that there is a known inputSelect component to which to add them. However, when creating components from fieldsets, one has to determine in realtime that a field in the set is a picklist. Then we have to create that inputSelect dynamically, and then create the inputSelectOptions after generating the inputSelect component, then add the entire bundle to a dynamic form component. 

The component containing all of this looks ike this:
<aura:component controller="ltngController">
    <aura:attribute name="userId" type="String" /><!--used to find the Contact-->
    <aura:attribute name="contact" type="Contact"/>
    <aura:attribute name="fieldSetName" type="String"/>
    <aura:attribute name="fields" type="Object[]"/><!--custom FieldSetMember class-->
    <aura:attribute name="picklistValues" type="Object[]" /><!--custom picklistOptions class-->
    <aura:attribute name="form" type="Aura.Component[]"/><!--dynamic component where generated components will be placed-->

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <!--HTML and other Lightning components-->

    <div class="row">
            <div class="section">
                <div class="cell form">
                          {!v.form}   
                </div>
            </div>
        </div>
</aura:component
The JSController runs the doInit which calls the server and gets the fieldSet data. This data is moved into a custom FieldSetMember class whose properties are AuraEnabled. For picklists, a describe call gets the Picklist value for this field and stores them in a list of custom PicklistValues objects. All this and the Contact record is bundled into a wrapper object and sent back to the JSController callback method. 
Checking the Debug Log and the Chrome Inspector verifies that all the data is available in the component controller, so that's not the problem.

Next step is to dynamcially create the components to hold the fieldSetdata in a helper method called 'createForm'. When a picklist value is encountered, I run the following 
createForm : function(cmp) {
	var fields = cmp.get('v.fields');
        var obj = cmp.get('v.contact');
        for (var i = 0; i < fields.length; i++) {
            var field = fields[i];
            if (field.type == 'PICKLIST'){
                var picklistValues = cmp.get("v.picklistValues");//all values for all picklist fields
                $A.createComponent("ui:inputSelect",
                                              {"label":field.label,
                                               "aura:id":field.label,
                                               "value":obj[field.fieldName],
                                               "required":field.required},
                    function(newSelect){
                        if (newSelect.isValid()){ // loop through the values to create options
                            for (var i = 0; i < picklistValues.length; i++){
                                var pItem = picklistValues[i];
                                
                                if (pItem.fieldName == field.fieldPath){ //only create for values that 
                                                                         //match the field's options
                                    $A.createComponent("ui:inputSelectOption",
                                                                  {"label":pItem.ItemLabel,
                                                                   "text":pItem.ItemValue},
                                          function(newOption){
                                              if (obj[field.fieldName] == pItem.ItemValue)
                                                  newOption.set("v.value":true);
                                                         
                                                   // get the inputSelect component's options attribute
                                                  var options = newSelect.get("v.options");
                                                  options.push(newOption);
                                                  newSelect.set("v.options",options);
                                          });
                                }
                            }
                        }
                        // after all picklist options are created and pushed into the v.options 
                        // attribute of the created inputSelect component, it all gets pushed into 
                        // the main component's v.form.
                           var form = cmp.get("v.form");
                           form.push(newSelect);
                           cmp.set("v.form",form);
                    });
            }
        }
}

OK, so after checking with the debugger; statement, all of those components appear to be created correctly. However, when I run the process, the picklist fields appear, with the correct label, but the drop-down for each reveals no selectOptions, even though there is enough empty space in the dropdown to match the number of options that should be visible. Here is a screen show of the rendered page:

User-added image
Agai, looking at the inputSelectOptions using the debugger statement in the Chrome DevTools Inspector showed that even as they were being inserted into the inputSelect component's options list, they contained the expected data, and the inputSelect components are showing in the form tag alongside the other field types. 

But WHY do the values not appear????? Any help is appreciated

I am basically diving into Lightning Component Development as I generally learn faster applying examples to real-world problems. In this case, I am trying to replace a javascript button that launched a window with a Visualforce page that has its own styling, Unfortunately adding the launch as a quickAction will open the window, but I can't get the size to match the content, making it largely unusable, even with scroll bars. 

Instead, I figure since Lightning Components are so Javascript heavy anyway, why can't I just build a Lightning Component featuring a UI button, an APEX controller providing a method to return the record ID, and a js controller with a doInit()function that queries the record data, while the button click launches the newInterview() method which contains the original Javascript that opens the Visualforce page using the parameters from the current record. That's the idea anyway...

Here is how I tried to build it:

COMPONENT
<aura:component controller="AuraMethods" implements="flexipage:availableForAllPageTypes,force:lightningQuickAction,force:hasRecordId" access="global" >
	<aura:attribute name="opp" type="Opportunity"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <ui:button label="New Interview" press="{!c.newInterview}"/>
</aura:component>

JS CONTROLLER
({
	doInit : function(component, event) {
		var action = component.get(c.findOppById("v.recordId"));
        action.setCallback(this, function(a) {
            component.set("v.opp", a.getReturnValue());
        });
        $A.enqueueAction(action);
	}
})

({
    newInterview : function(component, event){
        if(component.get("v.opp.School_Interview_Type__c")== '3W' || component.get("v.opp.School_Interview_Type__c") == '3W+School'){ 
        	window.location.href = "/apex/AM_Time_Slots2?id="+component.get("v.opp.Id")+"&Name="+component.get("v.opp.Name"); 
        } 
        else{ 
        	alert('please do not make an appointment AM time when the School Interview Type not equals 3W,only need to confirm the following AM given in the school time.'); 
        }
    }  
})

APEX CONTROLLER
public with sharing class AuraMethods {
    @AuraEnabled
    public static Opportunity findOppByID(String OppId){
        return [Select id, Name, School_Interview_Type__c from Opportunity where Id = :OppId];
    }
}


That's pretty much it. The Component appears in the Custom Components section of my Lightning Page Layout for the Opportunity in the App Builder, but when I try to place it I get the following error:

'Action failed: c:InterviewScheduling$controller$doInit [c is not defined] doInit()@components/c/InterviewScheduling.js:10:30'

I know I'm still a bit green to JS, as well so I may have missed something. More important, I've seen several posts about the difficulty of getting a javascript button's functionality to work in Lightning. I really just want to be able to launch this Visualforce page from within the Opportunity and have it appear in all its glory rather than in some dinky popup window where I can't adjust the width in the settings. 

I appreciate all responses. Kindness and patience is appreciated. I will learn this. 

Thanks!

V

Hello Helpers


by mistake I  started  recursive  batch class  chain

In the batch  finsih()  method  I  inserted a call for the same batch

Now  I  have a  batc running for  half  day  I  can not stop  it

Abor  does  not work If  i try to abort  I  get the be,ow  message
Failed to Abort Job Unable to remove job from Apex Job Queue.

I  need to stop  this  somehow
What  opton I have?

In the specs  I sew  that  "You can submit up to 5,000 batches per rolling 24 hour period."

but  since start my batch run more then 5000 times    


regards
csaba
  • April 20, 2015
  • Like
  • 0

Our application logs the user into and opens a website in an iFrame in a Visualforce page. Our problem is that when the user leaves the iFrame page using a back button, or when closing the browser, he is still logged in to the external site. 

I'm attempting to use cascading actionFunctions, where the last one fires oncomplete of the first. 
 

<apex:page controller="iFramePageController" sidebar="false" >
   
    <apex:form >
        <apex:actionFunction action="{!logoutOfApp}" name="logoutOfApp" immediate="true" reRender="iFrame" oncomplete="return()">
            <apex:param assignTo="{!logout}" name="logoutSwitch" value="true"/>
        </apex:actionFunction>
        
         <apex:actionFunction action="{!Back}" name="return" />
       
         <apex:commandButton value="Back"  onclick="logoutOfApp()" />
       
    </apex:form>
    
    <apex:iframe src="{!iFrameUrl}" id="iFrame"/>
    
</apex:page>


Controller:
public class iFramePageController {
       
    private string retUrl;
    private string logoutURL = 'https://AppCompany.com/logout.jsp?submitOK=true';
    
    public PageReference Back() {
        
        return new pageReference(retURL).setRedirect(true);
    }

    public pageReference logoutOfApp(){
        return new PageReference(logoutURL);
    }

    public String getiFrameUrl() {
         if (logout)
              return logoutURL;
         else{
              ... lots of login code that initiates the iFrame
         }
    }


}
Clicking the Back button will call the logoutOfApp action function, which passes the true parameter to a boolean value, then refreshes the iFrame.

the getiFrameURL should now provide the logoutURL (since logout is now 'true') to the src value in the iFrame tag

Once the rerender is complete, I expected the 2nd function to be called Back(), which uses the retURL initially provided to the page to redirect the user back to that page. 

Currently this isn't working and the page basically refreshes with the iFrame intact. I was able to sucessfully call the logout function when using the onmouseover in the Back button, but it never made it to redirecting to the return page. 

The thought was that I could refresh the iFrame to the logout page, thus logging out the user, then get the user back to the original page ensuring that the user was truly logged out. 

Not sure why this isn't working. Any help much appreciated to get it working, or help kme understand why it either doesn't or cannot work would be appreciated. 

Thanks

VeMan


 
I am using a wrapper class to combine an sObject with a checkbox, then iterating over the wrappers in my list. The first column displays the checkbox, then a repeat tag iterates over a list of strings derived from the object fieldNames, allowing the table to render columns according to the object's fieldSet.

the 'fieldSetList' is a list of field Names and I'm using a dynamic APEX process so that the client can reconfigure their table by changing the value and their order in the field set on the custom object.

The table displays correctly, however I want to be able to sort the table by clicking on the column. To do this, I have tried to add an onclick call to an ActionFunction ('sortCLTable') to the column and sending the repeat tag's interation variable ('f') as a parameter: 'onclick="sortCLTable(f)"'

The ActionFunction's parameter should set the sortValue property in the controller, and run the sorttable method, but alas it does not. The table columns have no response whatsoever.
 
​<apex:page ...> 
<apex:form> 
   <apex:outputPanel id="thePanel">
       <apex:pageBlockTable value="{!CLWraps}" var="CLWrap"> 
             <apex:column headervalue="Select" > 
                  <apex:inputCheckbox value="{!CLWrap.selectbox}"/> 
             </apex:column> 
             
             <apex:repeat value="{!fieldSetList}" var="f" > 
                  <apex:column value="{!CWrap.CL[f]}" onclick="sortCLTable(f)"/> 
                     // I've also tried sortTable('f'), sortCLTable({!f}) and sortTable('{!f}')
             </apex:repeat> 

        </apex:pageBlockTable> 
    </apex:outputPanel> 
    
    <apex:actionFunction action="{!sortTable}" name="sortCLTable" reRender="thePanel">          
          <apex:param name="firstParam" assignTo="{!sortValue}" value="" /> 
    </apex:actionFunction> 
  </apex:form> 
</apex:page>

CONTROLLER contains:

public string sortValue {get; set;} 
public pageReference sortTable(){ 
    resetQueryWithSortValue(sortValue); 
    return null; 
}

Although the 'f' is working to set the column header and reference the correct field value. it doesn't appear to be passing through the onclick call as a parameter to the apex:Param value associated with the function, or to the controller's corresponding 'sortValue' property. I think I've written the page tags correctly...

Using ActionSupport instead appears to mess up the repeat function such that the column names no longer appear - not sure why. Neither do the columns sort. 

I can add more code from my example if needed, but figured this would describe the problem. Any help is much appreciated.

Thanks