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
Chris LitesChris Lites 

Get around master-detail validation in visualforce page

Hi,

I am running in to an issue that I have not been able to solve and I was hoping that someone might have an idea of how to fix it. I have a visualforce page that allows me to add and remove child junction objects called Opportunity Competotors to the parent Opportunity object. the Opportunity Competitor object joins the Opportunity and Account objects with Account being in a master-detail relationship and Opportunity is a parent object in a lookup relationship. So because of this the Account field is required.

I am able to add new Opportunity Competitor junction objects to the page by adding a new wrapper object, however, it will not let me delete the unsaved junction object without first entering in an Account that meets the filter criteria. This is annoying from an end user perspective because there is no reason that they should need to enter information for something that they are just trying to delete.

My issue seems to be that I cannot even get to the delete method (delWrapper) before the error is thrown. It appears to be entering the getter method for the wrapper class at the very top of the controller and then entering the getter method for the Opportunity Competitor in the Wrapper class. at this point, I have not been able to pass which action is being taken as the param in the delete command button gets passed after the rerender I believe and I am not even able to reach the delete or save methods before this validation that there is an Account is performed.

Any ideas about how to get around this would be greatly appreciated.

this code was based on an idea in Bob Buzzard's blog located here:
http://bobbuzzard.blogspot.co.uk/2011/07/managing-list-of-new-records-in.html

controller:
public with sharing class OppCompetitorInsertController {
	 
	 public List<OppCompetitorWrapper> wrappers {get; set;}/* {if((!OppCompetitorWrapper.isSaved) && (OppCompetitorWrapper.oppComp.Competitor__c != null))
	 												{
	 													
	 												}
	 												} set;}*/
	 public Integer testId {get; set;}
	 public static Integer toDelIdent {get; set;}
	 public static Integer addCount {get; set;}
	 private Integer nextIdent=0;
	 private ApexPages.StandardController controller;
	 public Opportunity oppRecord {get; set;}
	  
	 public OppCompetitorInsertController(ApexPages.StandardController controller)
	 {
	 	  system.debug('test1');
	 	  this.controller = controller;
	 	  if (!Test.isRunningTest())
	 	  {
				controller.addFields(new List<String>{'Id', 'Name'});
	 	  }
	 	  oppRecord = (Opportunity)controller.getRecord();
	 	  system.debug(oppRecord);
	 	  
	 	  
	 	  List<Opportunity_Competitor__c> currentCompetitorList = new List<Opportunity_Competitor__c>{};
	 	  currentCompetitorList = [select Name, Id, Competitor__c, Competitor_Details__c, Lost_To__c, Opportunity__c, Primary__c, Replaced__c, Relationship__c, Opportunity__r.Id,
	 	  								  Opportunity__r.Competitor_Replaced__c, Opportunity__r.Competitor_Lost_To__c, Opportunity__r.Competitor_Complemented__c, Opportunity__r.Primary_Competitor__c
	 	  						  from Opportunity_Competitor__c
	 	  						  where Opportunity_Competitor__c.Opportunity__c =: oppRecord.Id];
		  wrappers = new List<OppCompetitorWrapper>();
		  
		  for(Opportunity_Competitor__c oppcomp : currentCompetitorList)
		  {
		  	system.debug(oppcomp.Id);
		  	wrappers.add(new OppCompetitorWrapper(nextIdent++, oppcomp, true, false));
		  }
	 }
	 
	 
	  
	 public void delWrapper()
	 {
	 	system.debug('checkpoint1');
		  Integer toDelPos=-1;
		  for (Integer idx=0; idx<wrappers.size(); idx++)
		  {
			   if (wrappers[idx].ident==toDelIdent)
			   {
			    	toDelPos=idx;
			   }
		  }
		  system.debug('checkpoint2');
		  system.debug(toDelPos);
		  if (-1!=toDelPos)
		  {
		  		if((wrappers.get(toDelPos).oppComp.Relationship__c == 'Replaced') && (wrappers.get(toDelPos).oppComp.Primary__c))
		  		{
		  			oppRecord.Competitor_Replaced__c = null;
		  		}
		  		if((wrappers.get(toDelPos).oppComp.Relationship__c == 'Lost To') && (wrappers.get(toDelPos).oppComp.Primary__c))
		  		{
		  			oppRecord.Competitor_Lost_To__c = null;
		  		}
		  		if((wrappers.get(toDelPos).oppComp.Relationship__c == 'Complemented') && (wrappers.get(toDelPos).oppComp.Primary__c))
		  		{
		  			oppRecord.Competitor_Complemented__c = null;
		  		}
		  		if((wrappers.get(toDelPos).oppComp.Relationship__c == null) && (wrappers.get(toDelPos).oppComp.Primary__c))
		  		{
		  			oppRecord.Primary_Competitor__c = null;
		  		}
		  		
		  		if(wrappers.get(toDelPos).isSaved)
		  		{
		  			try
		  			{
		  				delete wrappers.get(toDelPos).oppComp;
		  				update oppRecord;
		  			}
				  	catch (DmlException e)
				  	{
				  		system.debug(LoggingLevel.ERROR, 'There was an error: ' + e.getMessage());
				  	}
		  			
		  			
		  		}
		  		system.debug('checkpoint3');
		   		wrappers.remove(toDelPos);
		  }
	 }
	  
	 public void addRows()
		 {
		  for (Integer idx=0; idx<addCount; idx++)
		  {
		   	wrappers.add(new OppCompetitorWrapper(nextIdent++, oppRecord, false, true));
		  }
	 }
	  
	 public void /*PageReference*/  save()
	 {
	 	
	 	
		List<Opportunity_Competitor__c> oppCompsToUpsert = new List<Opportunity_Competitor__c>();
		List<Opportunity_Competitor__c> oppCompsReplaced = new List<Opportunity_Competitor__c>();
		List<Opportunity_Competitor__c> oppCompsLostTo = new List<Opportunity_Competitor__c>();
		List<Opportunity_Competitor__c> oppCompsComplemented = new List<Opportunity_Competitor__c>();
		List<Opportunity_Competitor__c> oppCompsPrimary = new List<Opportunity_Competitor__c>();
		list<OppCompetitorWrapper> ocwsChangedIsSaved = new list<OppCompetitorWrapper>{};
		Integer errorCount = 0;
		
		for (OppCompetitorWrapper wrap : wrappers)
		{
			
			Integer ocCount = 0;
			oppCompsToUpsert.add(wrap.oppComp);
			if(!wrap.isSaved)
			{
				wrap.isNew = false;
				wrap.isSaved = true;
				ocwsChangedIsSaved.add(wrap);
			}
			
			if((wrap.oppComp.Relationship__c == 'Replaced') && (wrap.oppComp.Primary__c))
			{
				oppCompsReplaced.add(wrap.oppComp);
		  		
			}
			for(Opportunity_Competitor__c ocr : oppCompsReplaced)
			{
				if(ocCount > 0)
				{
					ocr.Relationship__c.addError('You can only have one primary competitor that is replaced.');
					errorCount++;
				}
				ocCount++;
			}
			ocCount = 0;
			
			if((wrap.oppComp.Relationship__c == 'Lost To') && (wrap.oppComp.Primary__c))
			{
				oppCompsLostTo.add(wrap.oppComp);
			}
			for(Opportunity_Competitor__c oclt : oppCompsLostTo)
			{
				if(ocCount > 0)
				{
					oclt.Relationship__c.addError('You can only have one primary competitor that is lost to.');
					errorCount++;
				}
				ocCount++;
			}
			ocCount = 0;
			
			if((wrap.oppComp.Relationship__c == 'Complemented') && (wrap.oppComp.Primary__c))
			{
				oppCompsComplemented.add(wrap.oppComp);
			}
			for(Opportunity_Competitor__c occ : oppCompsComplemented)
			{
				if(ocCount > 0)
				{
					occ.Relationship__c.addError('You can only have one primary competitor that is complemented.');
					errorCount++;
				}
				ocCount++;
			}
			ocCount = 0;
			
			if((wrap.oppComp.Primary__c) && (wrap.oppComp.Relationship__c == null))
			{
				oppCompsPrimary.add(wrap.oppComp);
			}
			for(Opportunity_Competitor__c ocp : oppCompsPrimary)
			{
				if(ocCount > 0)
				{
					ocp.Primary__c.addError('You can only have one competitor that is primary when a Relationship value has not been selected.');
					errorCount++;
				}
				ocCount++;
			}
			ocCount = 0;
	  	}
		   
		if(errorCount < 1)
		{
			if(!oppCompsReplaced.IsEmpty())
			{
				oppRecord.Competitor_Replaced__c = oppCompsReplaced.get(0).Competitor__c;
			}
			else
			{
				oppRecord.Competitor_Replaced__c = null;
			}
			
			if(!oppCompsLostTo.IsEmpty())
			{
				oppRecord.Competitor_Lost_To__c = oppCompsLostTo.get(0).Competitor__c;
			}
			else
			{
				oppRecord.Competitor_Lost_To__c = null;
			}
			
			if(!oppCompsComplemented.IsEmpty())
			{
				oppRecord.Competitor_Complemented__c = oppCompsLostTo.get(0).Competitor__c;
			}
			else
			{
				oppRecord.Competitor_Complemented__c = null;
			}
			
			if(!oppCompsPrimary.IsEmpty())
			{
				oppRecord.Primary_Competitor__c = oppCompsPrimary.get(0).Competitor__c;
			}
			else
			{
				oppRecord.Primary_Competitor__c = null;
			}
			
			try
		    {
		    	update oppRecord;
				upsert oppCompsToUpsert;
		    }
		  	catch (DmlException e)
		  	{
		  		system.debug(LoggingLevel.ERROR, 'There was an error: ' + e.getMessage());
		  	}
		}
		else
		{
			for(OppCompetitorWrapper ocw : ocwsChangedIsSaved)
			{
				ocw.isSaved = false;
			}
			ocwsChangedIsSaved.clear();
		}
		  
		  
		   
		  //return new PageReference('/' + Schema.getGlobalDescribe().get('Opportunity').getDescribe().getKeyPrefix() + '/o');
		//return new PageReference('/' + oppRecord.Id);
	 }
	 
	 public void methodOne() 
     {
      	  system.debug('entering method 1');
	      OppCompetitorWrapper selectedLine;
	
	      for(integer i = 0; i < wrappers.size(); i++)
	      {
	        if(wrappers[i].ident == testId)
	        {
	          wrappers[i].beingDeleted = true; 
	        }
	        system.debug(wrappers[i]);
	      	system.debug(wrappers[i].beingDeleted);
	      }
	      
	      
	      
	      
     }
	  
	 public class OppCompetitorWrapper
	 {
		 
		  public Integer ident {get; private set;}
		  public boolean isSaved {get; private set;}
		  public boolean isNew {get; private set;}
		  public boolean beingDeleted {get; set;}
		  public String tooManyReplacedError {get; set;}
		  
		  public Opportunity_Competitor__c oppComp {
		  	get{
		      	system.debug('oppComp.Id = ' + oppComp.Id);
		      	system.debug('isNew = ' + isNew);
		      	system.debug('isSaved = ' + isSaved);
		      	if((oppComp.Id == null) && (isSaved == false) && (isNew == false))
		      	{
		      		oppComp.Competitor__c = '0018000000t9eJq';
		      		return oppComp;
		      	}
		      	else if((oppComp.Id == null) && (isSaved == false) && (isNew == true))
		      	{
		      		system.debug('oppComp = ' + oppComp);
		      		
		      		Opportunity_Competitor__c oppComp2 = new Opportunity_Competitor__c(Opportunity__c = oppComp.Opportunity__c);
		      		system.debug('oppComp2 = ' + oppComp2);
		      		return oppComp2;
		      	}
		      	else
		      	{
		      		return oppComp;
		      	}
		          
		      } 
		      set;
		  }
		  public String backgroundColor {
		      get{
		      	system.debug('oppComp.Id = ' + oppComp.Id);
		      	system.debug('isSaved = ' + isSaved);
		        if(isSaved == true)
		          return '#eeeeef';
		        else 
		          return '#FFF';
		      } 
		      set;
		  }
		  
		  set<Id> idsToCheck = new set<Id>{};
		  public OppCompetitorWrapper(Integer inIdent, Opportunity opp, boolean isRecordSaved, boolean isRecordNew)
		  {
		  	   isNew = isRecordNew;
		  	   isSaved = isRecordSaved;
			   ident=inIdent;
			   oppComp = new Opportunity_Competitor__c(Opportunity__c = opp.Id);
			   tooManyReplacedError ='';
	  	  }
	  	  
	  	  public OppCompetitorWrapper(Integer inIdent, Opportunity_Competitor__c currentoppcomp, boolean isRecordSaved, boolean isRecordNew)
		  {
		  	   isNew = isRecordNew;
			   ident=inIdent;
			   isSaved = isRecordSaved;
			   oppComp = currentoppcomp;
			   tooManyReplacedError ='';
	  	  }
	  	  
	 }
}
page:
<apex:page standardController="Opportunity" extensions="OppCompetitorInsertController">
 <apex:form >
 
 
  
   <apex:actionFunction action="{!methodOne}" name="methodOneInJavascript" >
		<apex:param name="firstParam" assignTo="{!testId}" value="" />
   </apex:actionFunction>
	
 
 
   <apex:pageBlock title="Add Competitors">
   <apex:pageMessages />
   
					
      <apex:pageBlockTable value="{!wrappers}" var="wrapper" id="wtable" width="95%">
         
         
         <apex:column width="23px" style="background-color: {!wrapper.backgroundColor};">
         	<apex:outputLabel value="Primary: " for="primaryFieldId" style="font-weight: bold; padding-right:7px"/><br />
         	<apex:inputField value="{!wrapper.oppComp.Primary__c}" id="primaryFieldId"/>
         </apex:column>
         
         
         <apex:column width="440px" style="background-color: {!wrapper.backgroundColor};">
         	<apex:outputLabel value="Competitor: " for="competitorFieldId" style="font-weight: bold"/><br />
         	<apex:inputField value="{!wrapper.oppComp.Competitor__c}" style="height:20px; width:400px" id="competitorFieldId"/>
         </apex:column>
         
        
         
         <apex:column width="43px" style="background-color: {!wrapper.backgroundColor};">
         	<apex:outputLabel value="Relationship: " for="relationshipFieldId" style="font-weight: bold; padding-right:7px"/><br />
         	<apex:inputField value="{!wrapper.oppComp.Relationship__c}" id="relationshipFieldId"/>
         </apex:column>
         
         
         
         <apex:column width="105px" style="background-color: {!wrapper.backgroundColor};">
         	<apex:outputLabel value="Competitor Details: " for="compDetailsFieldId" style="font-weight: bold"/><br />
         	<apex:inputField value="{!wrapper.oppComp.Competitor_Details__c}" style="height:20px; width:300px" id="compDetailsFieldId"/>
         </apex:column>
         
         <apex:column width="14px" style="background-color: {!wrapper.backgroundColor};">
         	<apex:commandButton value="Delete" action="{!delWrapper}" rerender="wtable" style="width:40px">
            	<apex:param name="toDelIdent" value="{!wrapper.ident}" assignTo="{!toDelIdent}"/>
            	<apex:param name="beingDelTrue" value="true" assignTo="{!wrapper.beingDeleted}"/>
            </apex:commandButton>
         </apex:column>
         
         
          <!--
         <apex:column width="23px" style="background-color: {!wrapper.backgroundColor};">
		      			<div>
		      			
					    <apex:outputPanel onclick="methodOneInJavascript('{!wrapper.ident}')"  > 
					        test
					    </apex:outputPanel>
					    
       					</div>
       					 
		</apex:column>
        -->
         
      </apex:pageBlockTable>
      <apex:commandButton value="Add Row" action="{!addRows}" rerender="wtable">
         <apex:param name="addCount" value="1" assignTo="{!addCount}"/>
      </apex:commandButton>
      <apex:commandButton value="Save All" action="{!save}" rerender="wtable">
      </apex:commandButton>
   </apex:pageBlock>
 </apex:form>
</apex:page>

User-added image


 
Best Answer chosen by Chris Lites
ManjunathManjunath
Hi,

Use immediate="True" in the command button for cancel.

SF - attribute explanation
"immediate" - A Boolean value that specifies whether the action associated with this component should happen immediately, without processing any validation rules associated with the fields on the page. If set to true, the action happens immediately and validation rules are skipped. If not specified, this value defaults to false.

Regrds,
MCS