+ Start a Discussion
IvarIvar 

Problem with "rerender" and redirect

Hi everyone.

 

I have a bit of a problem that I have been trying to get around for quite awhile now. I wrote a previous post (http://community.salesforce.com/t5/Visualforce-Development/Problem-with-Component-in-javascript/m-p/190323#M25337) about a problem I had where I was trying to get around issues with one type of workaround I tried, but have been unable to resolve that.

 

Rather than focus on my current failed attempt at getting around this I am now presenting my problem as it is, in hope that someone out there might see this from another perspective and offer some insights.

 

What I have is a visualforce page with a controller extension that runs within an iframe in a custom object's page layout (see screenshot below). What this does is allow users to edit certain properties of a related object in-line on the current page layout, without having to open each line up. This is done by the user by clicking the "QuickEdit" link for each line, and then either "Save" or "Cancel".

 

visualforce page layout component

 

When the Save link is clicked (#3 on screenshot) I always want the controller to fire up, do some logic, including saving the record obviously, but then, based on the selection in one of the picklists (#4 on screenshot) I want the return to either just refresh the list (#2 on screenshot), or redirect the parent page (#1 on screenshot) to a different location.

 

I am able to easily hardcode this to always do one of the two by setting the "rerender" or "target" properties of the commandLink (#3), but I want this to change dynamically based on the selection in (#4).

 

Now the render properties are set in the attributes of the commandLink (#2) element and are thus already set when the controller receives the request making it impossible (I think) for me to manipulate the return target from the controller, so I have been trying to use javascript to do this, without much success. I have been trying to call a javascript function on the "onChange" event of the controlling element (#4), but the javascript can only access DOM elements and thus can only change the commandLink's "target" attribute, not it's VF-specific "rerender" property.

 

I hope I managed to describe what I am dealing with, and hopefully someone has a suggestion for me that might work.

 

Best regards,

Ivar

Best Answer chosen by Admin (Salesforce Developers) 
d3developerd3developer

I'm surprised (well, not that surprised) that the SF default is as an iframe.

 

Here is a workaround  that I am pretty sure will work for you:

 

 

<apex:commandLink action="{!saveRecord}" reRender="fwdFunction" onComplete="forwardFunction()" />

 

 

 

<apex:outputPanel id="fwdFunction">


  <apex:outputPanel rendered="{!myRecord.property == desiredValue}">
      function forwardFunction()
      {
         window.top.location.href = "{!$System.Page.newPage}";

      }
   </apex:outputPanel>
  <apex:outputPanel rendered="{!myRecord.property != desiredValue}">
      function forwardFunction()
      {

      }
   </apex:outputPanel>

</apex:outputPanel>

 

May seem a bit dirty but I've used it and it works.

 

All Answers

d3developerd3developer

Maybe I'm missing something but I think what you want to do is:

 

 

<apex:commandLink action="{!saveRecord}" rerender="innerList" />

 

 

Then in your controller:

 

 

public PageReference saveRecord()
{

   upsert customObject;
   if (customObject.property == desiredValue) {
        	PageReference newPage = new PageReference('newPage');
		return newPage.setRedirect(true);
  }

  return null;


}

 

That will forward the page whenever the property of the custom object equals the desired value.

 

IvarIvar

Hi d3developer and thanks for your reply.

 

What you are suggesting is indeed exactly what I am doing. This does however not give me the desired effect as what this will do is just send the newPage to the iframe.

 

What I want is that when the special conditions are met is not to get a rerender of "innerList", but instead the whole page to be redirected to the newPage.

 

EDIT:I should point out that I have tried using target="_parent" as well, which is probably correct based on what I am trying to do , but the rerender property seems to override the target information

 

d3developerd3developer
IvarIvar

Thanks again for your feedback and help d3developer. I appreciate it.

 

The example you point to is indeed what I am basing my implementation on. Only difference is that I cannot run it as a standalone Visualforce page, but need it to run as a Visualforce component within a standard page layout.

 

Regards,

Ivar

d3developerd3developer

You still shouldn't need an iframe in that case. Mind sharing your page source?

MikeGinouMikeGinou

It's a little hacky, but for what it's worth:

 

How about having multiple save links, with specific rendered properties ensuring only one is visible at a time. Combined with an actionSupport tied to the onChange of #4, you could flip a flag in your controller, trigger a rerender of your list which would change which of the save links was being displayed, allowing you to get either the rerender property you want, or completely omitting it and having the parent you want.

 

I'm guessing that it won't be ideal due to rendering delays on the triggering onChange, but it's something.

IvarIvar

Thanks again d3developer.  I don't mind at all. Here are the visualforce page and the apex controller. Keep in mind that this is a work in progress so it's not the cleanest of code :)

 

How can I avoid this being rendered as an iframe? I am using this as an inset on a page layout, and I thought the system would always render that in an iframe. (See my screenshot below)

 

Here is the visualforce page:

 

<apex:page sidebar="false"  standardController="CustomLead__c" extensions="VF_SaleLineItemController"> 
    <script language="javascript">
        window.onload = function resizeIframe() {
            var thisWindow = window.name;
            if(thisWindow){
                var iframes = parent.document.getElementsByName(thisWindow);
                if (iframes && iframes.length == 1) {
                    var height = document.body.scrollHeight;
                    iframes[0].style.height = height + "px";
                }
           }
        }
        
        function setTarget( link, value ){
           alert( link + " ---- " + value );
           var cmdLink = document.getElementById( link );
           var statusField = document.getElementById( value );
           
           alert( statusField.value );
           alert( cmdLink.target );
           alert( cmdLink.rerender );
           
           if( statusField.value == "Unnin sala" ){
           	cmdLink.target = "_parent";
           	//cmdLink.rerender = "null";
           }
           else{
           	cmdLink.target = "";
           	//cmdLink.rerender = "projectList";
           }
           
           alert('after');
           alert(cmdLink.target );
           alert( cmdLink.rerender );
        	
        }
    </script>

    <!--<apex:sectionHeader title="Edit Projects" subtitle="{!$User.FirstName} {!$User.LastName}"/>
    <p/>-->
    
    <apex:pageMessages />
    <apex:form >    
    
    <apex:actionFunction name="saveEdit" action="{!saveEdit}"/>
    
    <apex:pageBlock title="Bæta við nýrri Sölulínu" mode="edit">
      Vöruflokkur:   <apex:inputField value="{!newLine.plProductCategory__c}"/> 
      Afgreiðsla:   <apex:inputField value="{!newLine.plTransactionType__c}"/> 
      Staða:   <apex:inputField value="{!newLine.plStatus__c}"/>  
      
   
        <apex:commandLink action="{!add}">
            Create
             <apex:param name="parent" value="{!CustomLead__c.Id}"/>
        </apex:commandLink>
            
    </apex:pageBlock>
    
    <apex:pageBlock >
    <apex:outputPanel id="projectList">
    <table>
        <tr>
            <th style="width:40px"> </th>
            <th style="width:80px"> </th>
            <th style="width:90px">Vöruflokkur</th>
            <th style="width:90px">Afgreiðsla</th>
            <th style="width:90px">Staða</th>
            <th style="width:90px">Afgreitt?</th>
            <!--<th style="width:90px">Weighting</th>-->
            
        </tr>
        <apex:repeat value="{!lines}" var="p">
        <tr style="height:20px">
            <apex:outputPanel id="editRow" layout="none" rendered="{!p.Id == editLine.Id}">
                <td><apex:commandLink action="{!cancelEdit}" rerender="projectList">Cancel</apex:commandLink></td>
                <td><apex:commandLink action="{!saveEdit}"  rerender="projectList" target="_parent" id="cmdLink">Save</apex:commandLink></td>
                <td><apex:inputField rendered="{!p.Id == editLine.Id}" value="{!editLine.plProductCategory__c}"/></td>
                <td><apex:inputField rendered="{!p.Id == editLine.Id}" value="{!editLine.plTransactionType__c}"/></td>
                <td><apex:inputField rendered="{!p.Id == editLine.Id}" value="{!editLine.plStatus__c}" id="statusField" onChange="setTarget('{!$Component.cmdLink}', '{!$Component.statusField}')"/></td>
                <td></td>
             
            </apex:outputPanel>
            <apex:outputPanel id="viewRow" layout="none" rendered="{!p.Id != editLine.Id}">
                <td width='60' colspan='2'>
                    <a href="{!$Site.Domain}/{!p.Id}/e?retURL={!CustomLead__c.Id}" target="_top"><b>Edit</b></a>&nbsp;|&nbsp;
                
                    <apex:commandLink action="{!del}" onclick="return confirm('Ertu viss um að þú viljir eyða þessarri línu?')"><b>Del</b>
                        <apex:param name="delid" value="{!p.Id}"/>
                    </apex:commandLink>
                    | &nbsp;
                    <apex:commandLink action="{!edit2}" rerender="projectList">QuickEdit
                        <apex:param name="editid" value="{!p.Id}"/>
                    </apex:commandLink>
                    
                </td>
                
                <td><a href="{!$Site.Domain}/{!p.Id}" target="_top">{!p.plProductCategory__c}</a></td>
                <td>{!p.plTransactionType__c}</td>
                <td>{!p.plStatus__c}</td>
                <td>{!p.cbAfgreitt__c}</td>
                
            </apex:outputPanel>
        </tr>
        </apex:repeat>
    </table>
    </apex:outputPanel>
    </apex:pageBlock>

    </apex:form>
    
</apex:page>

 This is the controller extension:

 

 

public class VF_SaleLineItemController {
    

    public Id parentId{get;set;}
    public String javaString {get;set;}
     
    public SaleItemLine__c newLine {get;set;}
    public SaleItemLine__c editLine {get;set;}
   
      
    public VF_SaleLineItemController(ApexPages.StandardController standardController) {
        
        newLine = new SaleItemLine__c();
        editLine = new SaleItemLine__c();
    }
    public VF_SaleLineItemController() {
       
        newLine = new SaleItemLine__c();
        editLine = new SaleItemLine__c();
       
    }
    
   
    public SaleItemLine__c[] getLines(){
        Id parent = System.currentPageReference().getParameters().get('Id');
        return [SELECT plStatus__c, cbAfgreitt__c, plTransactionType__c, plProductCategory__c FROM SaleItemLine__c WHERE CustomLead__c =: parent ORDER By CreatedDate DESC];
    }
    
    public String getParam(String name) {
        return ApexPages.currentPage().getParameters().get(name);   
    }
    
    public PageReference add() {
        try {
            String strParent = getParam('parent');
    
      
            this.newLine.CustomLead__c = strParent;
            INSERT newLine;
            newLine = new SaleItemLine__c();
            editLine = null;
            
        } catch (Exception e) {
            ApexPages.addMessages(e);
        }
        return null;
    }
     
    public PageReference del() {
        try {
            String delid = getParam('delid');
            
            SaleItemLine__c line = [SELECT Id FROM SaleItemLine__c WHERE Id=:delid limit 1];
            DELETE line;
            
        } catch (Exception e) {
            ApexPages.addMessages(e);
        }
        return null;
    }
    
    public PageReference edit2() {
        try{
            String editid = getParam('editid');

            editLine = [SELECT CustomLead__c, plStatus__c, cbAfgreitt__c, plTransactionType__c, plProductCategory__c FROM SaleItemLine__c WHERE Id=:editId];
        }
        catch(Exception e){
            ApexPages.addMessages(e);
        }
        return null;
    }
    
    public PageReference cancelEdit() {
        editLine = null;
        return null;
    }
    
   
    public PageReference saveEdit() {
        try {
           
            UPDATE editLine;
            
        } catch (Exception e) {
            ApexPages.addMessages(e);
        }
        
        if( editLine.plStatus__c == 'Unnin sala' ){

            PageReference newPage = new PageReference('/' + editLine.Id + '/e?retURL=/' + editLine.CustomLead__c );
           
            newPage.setRedirect(true);
            editLine = new SaleItemLine__c();
            return newPage;
            
        }
        else{
            editLine = new SaleItemLine__c();
            return null;
        }
    }
        

}

 And here is a screenshot of my page layout:

 

 

 

Again my thanks for all the help.

Ivar

IvarIvar

Thanks for the idea MikeGinou, nice outside-the-box thinking going on there :)

 

I would however like to avoid the rendering delays you mentioned. But it's a possibility as a last resort.

 

Thanks :)

d3developerd3developer

I'm surprised (well, not that surprised) that the SF default is as an iframe.

 

Here is a workaround  that I am pretty sure will work for you:

 

 

<apex:commandLink action="{!saveRecord}" reRender="fwdFunction" onComplete="forwardFunction()" />

 

 

 

<apex:outputPanel id="fwdFunction">


  <apex:outputPanel rendered="{!myRecord.property == desiredValue}">
      function forwardFunction()
      {
         window.top.location.href = "{!$System.Page.newPage}";

      }
   </apex:outputPanel>
  <apex:outputPanel rendered="{!myRecord.property != desiredValue}">
      function forwardFunction()
      {

      }
   </apex:outputPanel>

</apex:outputPanel>

 

May seem a bit dirty but I've used it and it works.

 

This was selected as the best answer
IvarIvar

Thanks a bunch. I'll try this workaround and let you know how it turns out :)

IvarIvar

My best thanks d3developer for all the effort, this finally worked, thanks to your help!