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
SidMSidM 

Problems capturing input from VF page in extension class

We have a VF page which uses the Opportunity standard controller and an extension class called ManageLineItems.cls.

 

One of the key actions a user can perform on this VF page is to auto-generate a quote by clicking a button, so we need to display a couple of fields in this VF page which belong to our custom 'quote' object, such as the validity period (date), among other fields.

 

For some reason, the changes to these fields made on the VF just aren't fed through to the extension class and we can't figure out why. What makes it even more puzzling is that the inputField appears to be bound correctly to the value, as it shows the default value specified by the setter (Date.today() + 14).

 

Any help would be greatly appreciated!

 



Simplified code extract:

 

public class ManageLineItemController {
public BC_Quote__c quote;
public BC_Quote__c getQuote() {
if (quote == null) {
quote = new BC_Quote__c(Valid_Until__c = Date.today() + 14);
}
return quote;
}

// NB: we have also tried the following standard getter/setter approach

public BC_Quote__c quote {
get {
if (quote == null) {
quote = new BC_Quote__c(Valid_Until__c = Date.today() + 14);
}
return quote;
}
private set;
}

public PageReference createQuote() {

// this ignores the date posted from the VF page

System.debug('createQuote(): validityPeriod = ' + quote.Valid_Until__c);

return null;
}
}

 

And the simplified VF example:

 

<apex:page standardController="Opportunity"
extensions="ManageLineItemController"
sidebar="false"
tabStyle="Opportunity">

<apex:inputField id="validityPeriod" value="{!quote.Valid_Until__c}" required="true" />
<apex:commandButton action="{!createQuote}" value=" Create Quote " />
</apex:page>

 
I may well be missing something really obvious, so please feel free to hurl insults if so! ;-)

Message Edited by SidM on 09-14-2009 07:18 AM
ThomasTTThomasTT

Did you just try your simplified code? because, it's working...

The field shows 9/28/2009, I changed it to 9/14/2009, and clicked the button, and log said it's 9/14/2009...

(I'm going to delete your source code in my org now...)

 

ThomasTT 

 

public class ManageLineItemController {

public ManageLineItemController(ApexPages.StandardController controller) {

}

public BC_Quote__c quote;
public BC_Quote__c getQuote() {
if (quote == null) {
quote = new BC_Quote__c(Valid_Until__c = Date.today() + 14);
}
return quote;
}


public PageReference createQuote() {
// this ignores the date posted from the VF page
System.debug('createQuote(): validityPeriod = ' + quote.Valid_Until__c);
return null;
}
}

 

 

<apex:page standardController="Opportunity"
extensions="ManageLineItemController"
sidebar="false"
tabStyle="Opportunity">
<apex:form>
<apex:inputField id="validityPeriod" value="{!quote.Valid_Until__c}" required="true" />
<apex:commandButton action="{!createQuote}" value=" Create Quote " />
</apex:form>
</apex:page>

 

 

Message Edited by ThomasTT on 09-14-2009 08:00 PM
SidMSidM

You are quite right... I over-simplified the post - my apologies.

The actual problem seems to be due to the fact that we are using a modal window (as per the YUI tutorial on the developerforce wiki) in order to capture the validity period.

If you take the revised example below, placing the inputField inside the modal dialogue forces the user input to be ignored, whereas simply placing the exact same inputField outside the modal dialogue, the user input is preserved.

Perhaps this is a side-affect of some of the DOM manipulation performed by YUI, which is throwing out the binding VisualForce requires?? Nothing substantial to prove that yet though.

I think my next step will be to try an alternative modal dialogue solution and see if the same thing happens.

Here's my current sample code (I set up a fresh test harness, so please forgive the minor name changes in the code since the last example):

 

<apex:page standardController="Opportunity"
extensions="TestQuoteWindowController"
sidebar="false"
tabStyle="Opportunity">

<apex:styleSheet value="{!URLFOR($Resource.YUI,'skin.css')}" />
<apex:includeScript value="{!URLFOR($Resource.YUI,'yahoo-dom-event.js')}" />
<apex:includeScript value="{!URLFOR($Resource.YUI,'container-min.js')}" />
<apex:includeScript value="{!URLFOR($Resource.YUI,'animation-min.js')}" />

<!-- YUI Functions -->
<script>
// Create a namespace for our custom functions
YAHOO.namespace("force.com");

// Function called when we want to show the dialog
YAHOO.force.com.showMe = function() {
document.getElementById("quotePanel").style.display = "block";
YAHOO.force.com.quotePanel.show();
}

// Function called when we want to hide the dialog
YAHOO.force.com.hideMe = function() {
YAHOO.force.com.quotePanel.hide();
}

// Function called when the DOM is ready to create the dialog,
// render the dialog into the document body, add our dialog skin
// css to the body tag, and wire up the buttons on our dialog
YAHOO.force.com.init = function() {
document.body.className = document.body.className + " yui-skin-sam";

YAHOO.force.com.quotePanel = new YAHOO.widget.Panel(
"quotePanel", // The id of our dialog container
{
visible : false, // Should be invisible when rendered
draggable : true, // Make the dialog draggable
close : true, // Don't include a close title button
modal : true, // Make it modal
fixedCenter : true, // Keep centered if window is scrolled
zindex : 0, // Make sure it's on top of everything

// This line adds the appear/vanish fade effect
effect : {
effect:YAHOO.widget.ContainerEffect.FADE,
duration:0.35
}
}
);

// Render the dialog to the document.body level of the DOM
YAHOO.force.com.quotePanel.render(document.body);
}

// Add the init method to the window.load event
YAHOO.util.Event.addListener(window, "load", YAHOO.force.com.init);
</script>

<apex:form >

<apex:commandButton value="open window" onClick="YAHOO.force.com.showMe();return false;" />
<div id="quotePanel" style="display:none;">
<apex:inputField id="validityPeriod" value="{!quote.Valid_Until__c}" required="true" />

<apex:commandButton action="{!createQuote}" value="Create Quote" onclick="YAHOO.force.com.hideMe();" rerender="table" />
</div>

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

 ... and the extension class

public with sharing class TestQuoteWindowController {

public TestQuoteWindowController(ApexPages.StandardController controller) {

}

public BC_Quote__c quote {
get {
if (quote == null) {
quote = new BC_Quote__c(Valid_Until__c = Date.today() + 14);
}
return quote;
}
private set;
}

public PageReference createQuote() {
// this ignores the date posted from the VF page
System.debug('createQuote(): validityPeriod = ' + quote.Valid_Until__c);
return null;
}
}

So now, all I have to do is move the single inputField outside the modal window, and the user input will be preserved.

<apex:page standardController="Opportunity"
extensions="TestQuoteWindowController"
sidebar="false"
tabStyle="Opportunity">

<apex:styleSheet value="{!URLFOR($Resource.YUI,'skin.css')}" />
<apex:includeScript value="{!URLFOR($Resource.YUI,'yahoo-dom-event.js')}" />
<apex:includeScript value="{!URLFOR($Resource.YUI,'container-min.js')}" />
<apex:includeScript value="{!URLFOR($Resource.YUI,'animation-min.js')}" />

<!-- YUI Functions -->
<script>
// Create a namespace for our custom functions
YAHOO.namespace("force.com");

// Function called when we want to show the dialog
YAHOO.force.com.showMe = function() {
document.getElementById("quotePanel").style.display = "block";
YAHOO.force.com.quotePanel.show();
}

// Function called when we want to hide the dialog
YAHOO.force.com.hideMe = function() {
YAHOO.force.com.quotePanel.hide();
}

// Function called when the DOM is ready to create the dialog,
// render the dialog into the document body, add our dialog skin
// css to the body tag, and wire up the buttons on our dialog
YAHOO.force.com.init = function() {
document.body.className = document.body.className + " yui-skin-sam";

YAHOO.force.com.quotePanel = new YAHOO.widget.Panel(
"quotePanel", // The id of our dialog container
{
visible : false, // Should be invisible when rendered
draggable : true, // Make the dialog draggable
close : true, // Don't include a close title button
modal : true, // Make it modal
fixedCenter : true, // Keep centered if window is scrolled
zindex : 0, // Make sure it's on top of everything

// This line adds the appear/vanish fade effect
effect : {
effect:YAHOO.widget.ContainerEffect.FADE,
duration:0.35
}
}
);

// Render the dialog to the document.body level of the DOM
YAHOO.force.com.quotePanel.render(document.body);
}

// Add the init method to the window.load event
YAHOO.util.Event.addListener(window, "load", YAHOO.force.com.init);
</script>

<apex:form >

<apex:commandButton value="open window" onClick="YAHOO.force.com.showMe();return false;" />

  <apex:inputField id="validityPeriod" value="{!quote.Valid_Until__c}" required="true" />

<div id="quotePanel" style="display:none;">
<apex:commandButton action="{!createQuote}" value="Create Quote" onclick="YAHOO.force.com.hideMe();" rerender="table" />
</div>

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

Message Edited by SidM on 09-15-2009 05:42 AM
ThomasTTThomasTT

 oh my... I alreay deleted the code... but I've done YahooUI modal things many times before and it should work.

It's display:none so that it is supporsed to be working, but my code always

 

  <apex:inputField id="validityPeriod" value="{!quote.Valid_Until__c}" required="true" />

<apex:commandButton action="{!createQuote}" value="Create Quote" oncomplete="YAHOO.force.com.hideMe();" rerender="table" />

 

 

 because, you need to show message on the modal popup if error occures... anyway, onclick happens before action method calling. That may one thing you can try.

 

But, I guess you still over-simplified your code... if you see the blog post, you are supposed to be using double-form for main and the modal popup and that may affect on reRender (actually, id structure is the problem).

 

I'll try your code if I have time, but please make sure that this simplified code doesn't work. It seems fine except the oncomplete one (and I think onclick should work, too...)

 

 

 

SidMSidM

Hi ThomasTT,

Thanks for replying. Actually, I have already tested the exact code I posted (didn't want to look stupid twice!). Using oncomplete or onclick is beside the point really. The test case above works fine if the inputField isn't place inside the modal window under YUI's control.

As far as displaying errors goes, that too works fine in our real page. We hide the modal window once the user clicks 'create quote' and any errors are rendered to the <apex:messages /> tag no problem.

There may be some detail I'm missing from the YUI tutorial which is causing this side-affect. I'll still looking into it and will post as soon as I find anything more.

Thanks for your help so far :-)

Message Edited by SidM on 09-15-2009 07:07 AM
ThomasTTThomasTT

This is interesting. Mr. Ron Hess could answer that in a second (because he already mentioned that), but it's about <apex:form>. It seems that once you use <div> for some fields,  <apex:form> can't recognize the fields. That's why, new <apex:form> is requred IN THE <DIV>... that's the reason why he used 2 forms.

 

 

<apex:form >
<apex:commandButton value="open window" onClick="YAHOO.force.com.showMe();return false;" />
</apex:form>
<div id="quotePanel" style="display:none;">
<apex:form>
<apex:inputField id="validityPeriod" value="{!quote.Valid_Until__c}" required="true" />
<apex:commandButton action="{!createQuote}" value="Create Quote" onclick="YAHOO.force.com.hideMe();" rerender="table" />
</apex:form>
</div>
</apex:page>

 

 This worked. I used the 2nd form (and even apex:actionRegion) without no question based on his blog post, but now I know why (but I still don't know the exact reason why single-form doesn't work...)

 

Anyway, I hope this solved your problem :)