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
TehNrdTehNrd 

Data Binding Not Working in jQuery Dialog Box

Something strange is going on and I can't figure it out. Data binding to variables in an Apex controller is not working if the <apex:input> tags are within a jQuery UI Dialog box. I've confirmed action method executes when called from a dialog box and rerenders are working but data binding is not. Unfortunately all else I can can provide is this very simple page to reproduce and then hope someone can help figure this out.

 

Page:

 

<apex:page controller="JQDialog">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js"/>
    <apex:stylesheet value="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/themes/ui-lightness/jquery-ui.css"/>
    
    <script type="text/javascript">
        var j$ = jQuery.noConflict();
        
        j$(document).ready(function(){
            //Creat modal
            j$("#popup").dialog();
        });
    </script>
    
    <apex:outputPanel id="count">
        Count: {!count} <br/>
        Checkbox: {!myCheckBox} <br/>
        String: {!myString}
    </apex:outputPanel>
    
    <apex:form >
        <div id="popup">
            <apex:inputCheckbox value="{!myCheckbox}"/> <br/>
            <apex:inputText value="{!myString}"/> <br/>
            <apex:commandButton value="Do Something" action="{!doSomething}" rerender="count" oncomplete="closeModal();"/>
        </div>
    </apex:form>
</apex:page>

 Controller:

 

public class JQDialog {

    public Integer count {get; set;}
    public Boolean myCheckbox {get; set;}
    public String myString {get; set;}
    
    public JQDialog(){
        count = 0;
    }

    public void doSomething(){
        count++;
    }
}

 

 

Thanks,

Jason

 

 

Best Answer chosen by Admin (Salesforce Developers) 
TehNrdTehNrd

Props to Richard Tuttle (@_drako), http://twitter.com/_drako/statuses/23458380660084736 , for figuring this one out. What jQueryUI does is move the div you define as the dialog box to the bottom of the DOM structure. This moves the input elements outside of the form and they are never sent back to the controller for processing.

 

Solution? Find a modal library that does not move the div you define as the modal outside of the form, or build your own.

All Answers

TehNrdTehNrd

Props to Richard Tuttle (@_drako), http://twitter.com/_drako/statuses/23458380660084736 , for figuring this one out. What jQueryUI does is move the div you define as the dialog box to the bottom of the DOM structure. This moves the input elements outside of the form and they are never sent back to the controller for processing.

 

Solution? Find a modal library that does not move the div you define as the modal outside of the form, or build your own.

This was selected as the best answer
rtuttlertuttle

No problemo.  I remember this issue far too well.  It used to work fine in YUI but then quit after an update.  Here is a pretty good description of why we can't move it from where it is (has to be child of body element for proper rendering).

 

http://forum.jquery.com/topic/preventing-dialog-from-rearranging-dom-flow

 

They also cover a duct tape way of fixing form binding issues using callback methods and hidden input fields.  Defeats the purpose in VisualForce slightly because of re-rendering items on the fly.  With a little more work it could be done in other methods like onchange, etc.  I remember using that as a solution once for a page with several dialogs and I don't really recommend it because it is a major pain in the rear to keep updated.  Another trick I tried at one point was using the apex:param component to directly write back to the controller from an actionfunction within the form.  Lot's of duct tape to get this one working.  I gave up and stopped using inputs on dialogs.

mtbclimbermtbclimber

Doesn't apply to all use cases but a solution I utilized for a login/register dialog box on a site I worked on involved loading the form into an iframe in the dialog which had the side benefit of leaving viewstate out of the majority of my pages.

rtuttlertuttle

Yea, I've done that before with jQuery dialog but one problem I've always had is getting iframes to size properly.  Bane of my existence.  How did you overcome that issue? With a login I'd guess it would be mostly static size.  The content I had was slightly dynamic.  I managed to resize with javascript, but height never came out quiet right; always had a bit of extra height in the frame.

 

 

-Richard

mtbclimbermtbclimber

Yes, it's a pain. The thing most forget to do is add the event handler to resize the iframe when the window is resized (i.e. maximized). I don't recall having "extra space" but then again, I didn't test *every* browser out there either ;-) 

 

And yes, fortunately for my case the form was static though it did have to be oversized to account for error messages and font size variations. Guess I could have applied the resize js business but I try to avoid pain when I can.

 

 

Abhinav GuptaAbhinav Gupta

agreed with @drako's view. All such overlay stuff like jquery dialog, colorbox or YUI overlay's move the div to be shown in popup in a couple of wrapped divs. So component tree structure breaks.

 

We previously created similar dialogs in visualforce manually by tweaking popup div's position to absolute, higher zindex etc.

 

For one customer, I used hidden fields to copy the state across popup mock input fields and actual view state. 

Also, opening the stuff in iframe is also a good appraoch, that worked for us with colorbox, but this is good only if iframe doesn't needs to share viewstate and communicate back to the parent page.

 

I was planning to do a blog post on the solution I developed, but was hesitant because of enourmus code (CSS,JS) invovled. Will try trimming and posting it sometime.

 

Please let me know, if you find any existing library, it will be huge help.

d3developerd3developer

Sorry to be late to the party...

 

I've a bunch of pages that do not exhibit this behavior. Here are two speculative and one certain reason why:

 

(1) Putting everything, including the form, in a wrapper div.

 

(2) Putting popups at the top of the page, the first thing inside a form.

 

(3) Putting the form inside the popup.

 

 

(3) definitely works although it is definitely bad practice if there is more than one form on a page. I'm looking at other examples that work which do not have the form inside the popup, and assume that (1) or (2) is responsible.

 

 

TehNrdTehNrd

Thanks for input Joel.

 

1) Does not work, only works if you put form inside the div you are making a modal (see #3)

2) Negative, didn't work for me

3) Multiple form tags.This one seems to work best but it is "bad".

 

Anyone (mtbclimber) know how bad multiple form tags actually are? Is there any difference other than a minor rise in the size of the viewstate? Whether all of the data is in one form or two the data portion of the view state would be the same, right? The only thing different would be the overhead for managing multiple form, which I've heard isn't that much.

 

Thoughts?

 

-Jason

d3developerd3developer

Jason,

 

Sad that (1) & (2) didn't work. If I get the chance I will go through old code to see if there is any other reason why my dialog boxes are working.

 

As for (3), I think the full viewstate is included with each form that goes on a page, so if you have a 2K viewstate then your page quickly goes from >2K to >4K. I'd love to have that understanding corrected though...

TehNrdTehNrd

Messing with multiple forms and a completely empty controller this is what I found:

 

1 form: 2.33KB

2 form: 2.36KB

3 form: 2.41KB

4 form: 2.44KB

 

There must be some other reason why multiple form are bad. This minor increase in viewstate doesn't justify the bad rap.

d3developerd3developer

Is that viewstate per form or viewstate total?

 

You might try measuring load time with Hammerhead too...

 

Let me know if there is something I can do here.

TehNrdTehNrd

It is using the viewstate inspector.

 

Posted that above before seeing your post. Did some more testing with actual data. Simple list of 13 accounts with 10 fields queried. Page uses repeat to render 4 input fields per record.

 

1 form: 5.19KB

2 form: 5.61KB

3 form: 5.97KB

4 form: 6.31KB

 

Jumps more than .03KB in previous test but it is definitely not doubling for each form.

rtuttlertuttle

I've run a page with multiple forms.  It didn't really cause many problems after version 18 of the API.  Before that I saw some strange issues with data not passing from form to controller in some cases.  Also the viewstate gets copied into each of the forms.  It causes more data to be transferred from the controller to the view and slows the loading down a bit.  This only really ever impacted our APAC located staff due to the already slow transfer rate.

 

As for the dialog box, mine worked for quite some time until an update.  Have you tried older API versions for the page?  Doubt it will work but might be worth a shot.

 

 

-Richard

TehNrdTehNrd

Interesting, when viewing a page with dev mode there is only one viewstate (probably view state of the editor) passed back and forth but when I disable this I see a view state in the HTML source for each form on the page, so yes this would hinder page load performace.

d3developerd3developer

Makes sense all around. I mean that if the viewstate was 2K then the page would def. be >2K and potentially, as in your case, around 6k.  if you had 2K (viewstate) + 4K, then I'd expect to see each form increase the page size by 2K (e.g. 6K, 8K, 10K, etc.).  Sorry if that wasn't clear.

 

I think what this means is that you can use the multiple form approach if you don't have a particularly large viewstate.

rtuttlertuttle

Someone recently posted an article out on improveit360 at blogspot.  I forgot about this posting when I read it but Gotcha #3 has a solution for this exact problem in jQuery.

 

http://improveit360.blogspot.com/2010/09/gotchas-using-jqueryui-to-make-popups.html

 

 

-Richard

Jennifer SimondsJennifer Simonds
OMG thank you! This problem had been bugging me for weeks. Moving the apex:form inside the dialog works perfectly.