+ Start a Discussion

Clone override

Hi there,


I have created three VF pages (view, edit and new) to display my data in three columns and have overridden the relevant buttons, but I'm having a bit of trouble with the clone override. I can get the clone to work using this syntax in the view VF page:


<apex:commandButton action="{!UrlFor($Action.CustomObject__c.Clone,CustomObject__c.Id)}" value="Clone"/>

 This returns a standard clone page with the URL:





This works a treat apart from two things:


1. Pressing 'Cancel' returns a blank ViewCustomObject page. How can I get 'Cancel' to return to the original Custom Object?


2. I want to display my data in three columns, so I set the 'Clone' override to my 'New' VF page, but the clone functionality doesn't work any more and I just get the original custom object in my 'New' VF page format. Is there any way to get the clone functionality to work with VF pages?


I dug around in the forums and found the following example syntax for a clone:


<apex:commandButton action="!UrlFor($Action.CustomObject__c.Clone,CustomObject__c.Id,[cloneli=1],true)}" value="Clone"/>

I tried this with the clone override I described above in point 2 and it just returned the standard clone page. Having checked out the documentation for URLFOR (http://www.salesforce.com/us/developer/docs/pages/index_Left.htm#StartTopic=Content/pages_variables_functions.htm?SearchType=Stem) I was wondering where people got the example syntax.


The documentation just specifies resource and path as attributes for the function, but the example syntax has two further attributes: [cloneli=1] and a boolean set to 'true'. Can someone please shed some light on this?



Message Edited by paddington on 12-05-2009 04:40 AM
For what it is worth, we had to override some of the clone logic (we wanted to change the behavior of an opportunity clone), so ended up building our own clone controller/VF, and adding our own "clone" button to the Opportunity page.
@insanedukepossee     Care to share your code?

Sorry, there's some spaghetti in this code, but it meets our need. And we took shortcuts in some places (ex: don't check if the products are still valid).


The primary thing we were trying to achieve was to NOT clone the revenue schedule (I don't think very many customers use this feature). There are other differences - for example this does not put the user into edit mode of the new cloned but not saved record; This clones the record, saves it to the DB, then goes to that record.




public class OpportunityClone_Class { public Opportunity OldRecord {get; set; } public Opportunity NewRecord {get; set; } public Id OpptyIdOld {get; set; } public Boolean CloneOLI {get; set; } public Boolean forceError {get; set; } // this is the constructor public OpportunityClone_Class (){ //default forceError = False; //get the passed parm OpptyIdOld = System.currentPageReference().getParameters().get('id') ; if ( System.currentPageReference().getParameters().get('cloneoli') == '1') { CloneOLI = True ; } else { CloneOLI = False ; } } // this will be invoked from VForce page // in this kind of VForce page / controller, the constructor can not do the work public PageReference doit(){ //SPECIFICALLY EXCLUDE THESE FIELDS: //this gets the original record... OldRecord = [ Select AccountId , Amount , CampaignId , CloseDate , CreatedById , CreatedDate , CurrencyIsoCode , Description , Fiscal , FiscalQuarter , FiscalYear , ForecastCategory , HasOpportunityLineItem , Id , IsClosed , IsDeleted , IsWon , LastActivityDate , LastModifiedById , LastModifiedDate , LeadSource , Name , NextStep , OwnerId , Pricebook2Id , RecordTypeId , StageName , SystemModstamp , Type , (Select Id, OpportunityId , Description, PriceBookEntryId, Quantity, TotalPrice from OpportunityLineItems) from Opportunity o where id = :OpptyIdOld ] ; try { // clones the original (resets id) Opportunity NewRecord = OldRecord.clone(false, false); //over ride some fields NewRecord.Name = '[CLONED] ' + OldRecord.Name; NewRecord.Amount = 0; //for good or bad, not resetting the pricebookid - would cause lots of other problems //NewRecord.Pricebook2Id = null; //Closed deals can be any date. Non-Closed deals can only be future. if (!NewRecord.IsClosed) { NewRecord.CloseDate = system.today(); } //insert cloned record insert NewRecord; //this will cause a failure, i.e. the catch if (forceError) { insert NewRecord; } system.debug ('NEW RECORD: ' + newRecord.id + ' ' + newRecord.Name); if (CloneOLI == True) { OpportunityLineItem[] products = oldRecord.OpportunityLineItems.DeepClone(false); for (OpportunityLineItem each : products) { each.OpportunityId = NewRecord.id; each.TotalPrice = 0; //each.Description = '[CLONED]' + each.description; } insert products; } PageReference home = new PageReference('/' + newRecord.id); home.setRedirect(true); return home; } catch (Exception e) { system.debug ('ERROR! ' + e); ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.ERROR, 'Error creating new record: ' + e); ApexPages.addMessage(myMsg); return null; } } }





Thanks, I need to write one as well and it's pretty straightforward. I was just wondering if you had any pearls which I hadn't seen before.  If you're interested I could send you mine when I'm done with it.  (Although, like you, I've got some custom needs in it... otherwise we wouldn't be writing them in the first place!  :-) )


Best, Steve.