5

For some reason the second query in the constructor makes the Cancel button in my visualforce page not work. Does this have to do with some special quirk in PricebookEntry?

If you comment out the second query (the one that populates HwAndSwProducts) the cancel button works fine.

This is the controller:

public with sharing class ManageAddSupportController {

    public Opportunity opp { get; private set; } 
    public List<PricebookEntry> HwAndSwProducts { get; private set; } 

    public ManageAddSupportController() {
        //Populate controller properties
        opp = [SELECT name, id, Pricebook2Id FROM Opportunity 
            WHERE Id =: ApexPages.currentPage().getParameters().get('id')]; 

        //This is the query that if we comment out the Cancel works    
        HwAndSwProducts = [SELECT name, id, ProductCode, UnitPrice 
            FROM PricebookEntry WHERE Pricebook2Id =:opp.Pricebook2Id 
            AND (NOT name LIKE '%Service%')]; 
    }

    public PageReference cancelSupport() {
        System.debug('we want to cancel!!!');
        PageReference ref = new PageReference('/' + opp.Id);
        ref.setRedirect(true);
        return ref;         
    }
}

And this is the view:

<apex:page controller="ManageAddSupportController">

<h1>Opportunity {!opp.name}</h1>
<p>Please choose those products you'd like to add support to.</p>

<apex:form >
    <div style="text-align:center">
        <apex:commandButton action="{!cancelSupport}" value="Cancel" id="cancelAddSupport" />
    </div>
    <br/>
    <apex:pageBlock >
        <apex:pageBlockTable value="{!HwAndSwProducts}" var="product">
            <apex:column style="width: 5%">
                <apex:inputCheckbox value="{!product.Id}"/>
            </apex:column>
            <apex:column value="{!product.Name}"/>
            <apex:column value="{!product.ProductCode}"/>
            <apex:column value="{!product.UnitPrice}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:form>

When I add debugging statements in the cancel action I see that it's not even being called when that second query is present. If you look at the logs it seems like the constructor is being called again. Very strange...

  • This is going to sound really stupid. Have to tried moving the commandbutton within the apex:pageblock before the table? The constructor is probably being called when you click the button because it's trying to refresh the page vs calling your action method. – Salesforce Wizard Nov 9 '12 at 16:35
  • I tried. Didn't make a difference. The constructor instead of the the cancel action is still being called. :( – ceiroa Nov 9 '12 at 16:39
  • Ya. I'm just brain storming weird stuff. None of this SHOULD make a difference, but we can try it anyways. I don't see anything in the code that would cause your method not to work just because of a SoQL query. Assuming that doesn't work. Create another method that doesn't nothing. Seriously nothing. Well do a system.debug And see if your button/link will call that. So let's try some fun stuff. Keep your commandbutton, and add a command link. See if there's a difference. – Salesforce Wizard Nov 9 '12 at 17:10
  • I have tried both things already. A method that does nothing does not get called from either a commandbutton or a commandlink as far as that query is there. And what is super strange is that the query works fine. I mean, I can see the items in the page. It's not that the query is wrong or anything. – ceiroa Nov 9 '12 at 17:17
  • I have even tried in a different org to make sure it wasn't some org-specific issue... – ceiroa Nov 9 '12 at 17:25
7

This was a tricky one, adding this to the Visualforce page

<apex:pageMessages />

finally grassed up the culprit !

Incorrect Binding !

This is the offending binding :

 <apex:inputCheckbox value="{!product.Id}"/>

You're binding a boolean to an Id field, which fails conversion at runtime.

Commenting out this line makes the Cancel button work just fine.

If you intend using a checkbox to select Products, make use of the wrapper pattern, where you can have a boolean instance variable for selection.

http://wiki.developerforce.com/page/Wrapper_Class

P.S. As for the mystery of why commenting out the second SOQL query makes it works - no Products selected, so no Runtime Exception converting Boolean to Id.

| improve this answer | |
  • Hah, that's it! :) Thanks much. This makes total sense. – ceiroa Nov 9 '12 at 21:43
  • Enjoyed that. Cheers ! – techtrekker Nov 9 '12 at 21:45
  • Nice sleuthing @techtrekker – Ralph Callaway Nov 9 '12 at 22:25
  • 1
    Great answer, It is my opinion that every visualforce page should include pageMessages no matter how simple – Daniel Blackhall Nov 10 '12 at 23:29
1

This "cancel" action (like any other button) is doing a postback to the controller. That's a lot of work (deserialize viewstate, perform basic checks on the data such as "were the fields marked as required actually filled in"...)

To bypass these checks use immediate="true" in your commandButton. Furthermore - I don't think you even need the whole cancelSupport function. URLFOR will do - and less code to maintain and provide code coverage is always a good thing.

Combine these 2 for maximum performance ;)

<apex:commandButton 
    value="Cancel"
    action="{!URLFOR($Action.Opportunity.View, opp.Id)}"
    immediate="true" />

Being able to modify the link in future right in the VF page (without redeploying the Apex) is just an added bonus!

EDIT Why do you have a custom controller actually? This page looks like a candidate to have standardController="Opportunity". Then your job would be even easier, action="{!view}" :)

| improve this answer | |
  • Your solution works. I'm still curious though, why wasn't the request from the commandbutton reaching the action method? Why would it work without the second SOSQL query but would not work with it? – ceiroa Nov 9 '12 at 18:49

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.