Trying to understand odd behavior in Ajax form

20 views
Skip to first unread message

Sriram N

unread,
Apr 26, 2015, 10:11:13 PM4/26/15
to lif...@googlegroups.com

I am using an Ajax form with lots of fields and a result div that changes when the form is submitted.  So as long as users are within the page they change fields and submit, the result div updates properly.  I store the set of form values and result div content so that if they navigate away from the page and come back to the Ajax form, it looks like they never left the page.  That is, all the form values are the same and the result div also is properly populated.

So imagine the user uses this Ajax form, navigates away and comes back to it. The content looks fine.  However when they try new form values the process method of the ajaxSubmit does work but the result div isn't updated and seems stuck (the SetHtml is being called correctly with the correct content inside process but nothing happens). If one  navigates away from the page and come back in which case the results look updated.  But again subsequent submits are stuck with the same result.  Summary:  If you do not navigate away from the page all is well.  If you do navigate away and come back and resubmit  the result div gets stuck (the workaround is to leave the page and come back). Oddly this happened only with one of the divs used for output (2 others were being correctly updated).

The simple fix that worked was to make 2 result divs with different names, one inside the process method and another used at the end of render.  

In summary the oddness in the before situation was as follows

// umethod, emethod, resultmethod populate the 3 divs with NodeSeqs on page refresh. On ajax submit process does a similar thing for these divs.
// while udiv and ediv were being correctly updated even after navigation to different page the resultdiv stuff got stuck even though process was working and the other methods were not called on submit

"#udiv" #> umethod &   // umethod provides last known form submission of user for udiv
 "#ediv" #> emethod &  // likewise for ediv
 "#resultdiv" #> resultmethod &  //ditto for resultdiv
 "type=submit" #> ajaxSubmit("Query", process)  // process updates the same divs above  However it does not do so for resultdiv in the situation described above even though the dump of the NodeSeq  in the log is correct.


So the most important content resultdiv had this annoying property. The simple fix was to create another div resultolddiv so that the process and standalone methods target different result divs.

So the fix that resolved this annoyance was

"#udiv" #> umethod &   
 "#ediv" #> emethod &
 "#resultolddiv" #> resultmethod &
 "type=submit" #> ajaxSubmit("Query", process)  // process updates udiv, ediv but not resultolddiv.  Instead it targets resultdiv.

So this keeps both divs happy and out of each others way. As to why this oddness is not seen for udiv and ediv beats me (maybe they are simpler content).   




Sriram N

unread,
Apr 26, 2015, 10:14:26 PM4/26/15
to lif...@googlegroups.com
I should mention that the actual div name was simply "result" in case that name has some significance (the others were more convoluted).

Sriram N

unread,
Apr 26, 2015, 10:19:14 PM4/26/15
to lif...@googlegroups.com
And that I used span tags not divs, if that is relevant.
 
<p  id="urldiv">Link appears here</p>
<span id="effecttypelabel"></span>
 <span id="result"></span>
 <span id="result0"></span>

Sriram N

unread,
Apr 27, 2015, 9:00:53 PM4/27/15
to lif...@googlegroups.com

Let me try to rephrase the basic issue. I suspect that I am not using the correct pattern or syntax in the render method for this use case. Hope this attempt makes it clearer.

There are 2 different scenarios: (1) Ajax form is loaded for the first time  and (ii) We are already in the page and Ajax button is submitted (possibly multiple times, each time for a new result)
Let us assume that the target element ( has "result" id) is where the results are displayed.  The result happens to be bootstrap formatted table populated using a selector.

Now the render method returns a CssSel which is made of a number of CssSel connected with &.  Among these are 2 of interest in this case.

Line 1: "#result" #> resultmethod    //  resultmethod generates a NodeSeq by accessing a map where the last result is stored for a particular user.  Ideally this CssSel should only fire for page load or page reload and not for Ajax submits

and the actual submit button CssSel

 Line 2: "type=submit" #> ajaxSubmit("Query", process)    

process is a method that uses SetHtml to change the content of the result div. So it returns a JsCmd.  This will only fire when the Ajax button is submitted.  Not only does it change the result div, it also updates the map where the user last result is stored.

The problem is that I do not know how to ensure that the first line does not execute or influence the result div for Ajax button submits.  Depending on how result method is written it overwrites or appends to the content of result (which has already been populated by process); So either I end up seeing the old table or the new table followed by the old table in the div (odd side comment: I get 2 tables if I write code to generate the NodeSeq, newer table from SetHtml of process followed by older table from the resultmethod; I just get the old table if I use css selector in resultmethod to generate NodeSeq).  The weird thing is that on the very first access of the page (first load) I do not see this behavior. When I navigate away and reload and then do Ajax button submits, I do see this behavior.  This overwriting etc. would not be an issue if the Map were already updated before the resultmethod executed (apparently it is frozen and has the older value from the Map at the time when the page is loaded).  So the  fix is to somehow make Line 1 execute only for page loads and reloads and not for Ajax button submits. How would one do this conditional behavior inside the render method? A fix that I do not know how to make.

General comment:  Even if the documentation in Lift is incomplete or outdated, it would help newbies to get the right mental model of how Lift works, using current features and syntax.  I am sure this can be accomplished in under 10 pages with reference to the key types and sequencing of operations. My present mental model is this: Lift is not just about strings but manipulates the DOM using properly vetted NodeSeqs (by a html5 parser) which are generated by css selectors in the backend.  Are the css selectors at the end of the render method evaluated just once on page load or each time one submits the Ajax button? Is there any order to how the cssSelectors are evaluated (in linear order)?  Is there a way inside render to tell if this is a page reload or an Ajax submit?
Reply all
Reply to author
Forward
0 new messages