Lift M8 - strange javascript evaluation order

85 views
Skip to first unread message

Riccardo Sirigu

unread,
Mar 10, 2016, 9:59:52 AM3/10/16
to Lift
Hi everyone,

We bumped up our Lift version to the M8 and we are experiencing strange behaviors regarding javascript evaluation.

We have a snippet of code that checks if the user is logged in, if it is, it creates an ajax button with a javascript function as a target that shows a modal to allow the user to login. 
In case the user is already logged in, it perform another behavior not relevant for this question.

The problem is that is seems that the javascript function that we pass as a callback to the ajax button, gets evaluated during the render, causing strange behaviors..

Is something about javascript evaluation changed in the M8?
With the M6 was working perfectly.. the same is true with the M7 that I just tried

Antonio Salazar Cardozo

unread,
Mar 10, 2016, 1:45:07 PM3/10/16
to Lift
I think we'd need to see how exactly you're constructing the JS
that you expect to have run later. We only made a couple of fixes
between M6 and M8 that would have affected what it sounds like
you're describing. The biggest one was doing event extraction on
AJAX responses that include HTML, but that doesn't sound directly
related.

Anyway, if you could post an example project demonstrating the
issue I think we can try to figure out what's wrong.
Thanks,
Antonio

Riccardo Sirigu

unread,
Mar 25, 2016, 7:51:40 AM3/25/16
to Lift
I finally managed to replicate the problem in a test project


The problem is with the following code 


class Index {

 
def performCallback(action: JsCmd) = {
   
if(false) action else JsCmds.Noop
  }

 
//If i remove the id, everything works as expected
  def newButton(text: String): NodeSeq = {
   
SHtml.ajaxButton(text, () => Alert("To execute later!!"), "id" -> "my-button") //Alert executed multiple times
   
//SHtml.ajaxButton(text, () => Alert("To execute later!!"))
  }

 
def render = {
   
"#hello" #> SHtml.ajaxButton("Button", () => Alert("Hi from button") &
      performCallback
(Replace("my-button", newButton("New Button"))),
     
"id" -> "my-button")
 
}
}


After the first click of the button, the code inside performCallback(), (the Alert inside newButton), gets executed multiple times.. one time more for every click performed on the button

I know the problem can be caused by the id that is the same for both the ajax buttons, and some Lift low level machinery has trouble with this.. but why we hadn't experienced any problems with the M6?

Is there a way to solve this leaving the id as is?

Antonio Salazar Cardozo

unread,
Mar 26, 2016, 12:34:15 PM3/26/16
to Lift
Hey there,
Just had a quick look at this, but couldn't get the app running:

Mar 26, 2016 12:30:21 PM com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: ERROR - Cannot read: ~/github/liftWebProblem/src/main/javascript/views/user/Login.js

Mar 26, 2016 12:30:21 PM com.google.javascript.jscomp.LoggerErrorManager printSummary
WARNING: 1 error(s), 0 warning(s)
[error] JSC_READ_ERROR. Cannot read: ~/github/liftWebProblem/src/main/javascript/views/user/Login.js at (unknown source) line (unknown line) : (unknown column)

Looks like perhaps you forgot to commit those files?

At first blush, the issue should not be related to the id—Lift takes the
right hand side of a CSS bind expression as call-by-name, so it should
be re-evaluated for each matching button (incidentally, I didn't know this
and caused a bug in some early versions of Lift 3's bindings for user
forms in ProtoUser).

Would definitely like to investigate more though, so let me know when
that repo's runnable and I'll have a look!
Thanks,
Antonio

Riccardo Sirigu

unread,
Mar 26, 2016, 2:17:38 PM3/26/16
to Lift
Thank you for your time Antonio, it's runnable now

Antonio Salazar Cardozo

unread,
Mar 28, 2016, 2:14:28 PM3/28/16
to Lift
Hey Riccardo,
You're 100% right that the id is the reason this is triggering more
than once. However, if you were actually replacing the button, it
would not do this.

The reason this is happening is because the `Replace` JsCmd
eagerly handles the HTML that is passed to it. “Handling” in this
case involves extracting event handlers so they can be attached
without including them in the HTML directly (so that strict content
security policy can be applied). This extraction is done when the
JsCmd is converted to a JavaScript string, but due to the way
that `toJsCmd` is defined for `Replace`, this is done eagerly when
it is instantiated, rather than being done only if the command is
used.

I think we can change the way that this is handled a little bit so
that it isn't a problem, and I think this is worth blocking a release
on as it's a fair assumption that this would work the way that it
is currently written.

Can you please file an issue for it on the lift/framework repo?
Thanks,
Antonio

Antonio Salazar Cardozo

unread,
Mar 28, 2016, 11:32:46 PM3/28/16
to Lift
I went ahead and filed issue #1782 and will look at it this
week!
Thanks,
Antonio

Antonio Salazar Cardozo

unread,
Mar 29, 2016, 12:21:28 AM3/29/16
to Lift
And since I was feeling excited today, threw #1782 together to
fix the issue! I gave it a whirl locally with your test project and
everything seemed to work. If you get a chance to build and try
it yourself on your original project, that would be awesome!

If not, we'll let you know when we merge and the fix is available
in the SNAPSHOT branch.
Thanks,
Antonio

Antonio Salazar Cardozo

unread,
Mar 29, 2016, 5:27:40 PM3/29/16
to Lift
Heh. I meant #1783 the second time.
Thanks,
Antonio

Riccardo Sirigu

unread,
Mar 30, 2016, 4:00:48 AM3/30/16
to Lift
Thank you Antonio!
I'm trying to build from source right now

Antonio Salazar Cardozo

unread,
Mar 31, 2016, 2:11:02 PM3/31/16
to Lift
Any luck here?
Thanks,
Antonio

Riccardo Sirigu

unread,
Apr 1, 2016, 3:57:39 AM4/1/16
to Lift
It works perfectly now, 
thanks

Riccardo

Antonio Salazar Cardozo

unread,
Apr 1, 2016, 12:25:48 PM4/1/16
to Lift
Awesome! We'll be rolling out an RC2 this weekend with this
change :)
Thanks,
Antonio
Reply all
Reply to author
Forward
0 new messages