Re: [Lift] Signup validation
Hello, ticket created: http://www.assembla.com/spaces/liftweb/tickets/368 On Feb 24, 2010, at 6:28 PM, David Pollak wrote: On Wed, Feb 24, 2010 at 7:33 AM, Adam Warski a...@warski.org wrote: Hello, I'm integrating recaptcha into a Lift app that uses MegaProtoUser, and there's one small thing that I think can be improved. There is currently no good place to put the captcha-verifying code. After the signup form is submitted the user if validated using theUser.validate (ProtoUser.scala:386, testSignup method). However I can't put captcha validation into User.validate, as there won't be any captcha when e.g. editing a user. So I would propose adding a method to MetaMegaProtoUser, e.g.: protected def validateSignup(user: User) = user.validate which could be then overridden in concrete user classes. Sounds like a great addition. Please open a ticket on it. I'll get to it tomorrow (unless someone beats me to the punch.) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- Lift, the simply functional web framework http://liftweb.net Beginning Scala http://www.apress.com/book/view/1430219890 Follow me: http://twitter.com/dpp Surf the harmonics -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Signup validation
Hello, I'm integrating recaptcha into a Lift app that uses MegaProtoUser, and there's one small thing that I think can be improved. There is currently no good place to put the captcha-verifying code. After the signup form is submitted the user if validated using theUser.validate (ProtoUser.scala:386, testSignup method). However I can't put captcha validation into User.validate, as there won't be any captcha when e.g. editing a user. So I would propose adding a method to MetaMegaProtoUser, e.g.: protected def validateSignup(user: User) = user.validate which could be then overridden in concrete user classes. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Signup validation
Hello, Can't you just override actionAfterSignup and don't call super if captcha check fails? But that already assumes that signup was successfull and in the end redirects to the homepage instead of going back to the singup form. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Can I test Lift 2.0-M2 with Scala 2.0 Beta 1 now?
Hello, Question - Can I test Lift 2.0-M2 with Scala 2.0 Beta 1 now? you need to use code from the 280_port_refresh branch (http://github.com/dpp/liftweb). The milestones are for 2.7.7 still. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Comet shutdown?
Hello, Yes, in fact there is a timespan method in CometActor. You should be using Lift 2.0-M1 or 2.0-SNAPSHOT. I'm using 2.0-SNAPSHOT: class Test extends CometActor { def render = NodeSeq.Empty override def timespan = 0 } error: method timespan overrides nothing override def timespan = 0 ^ one error found same for timeSpan. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Snippet with no reflection an no massive case statement
All i would like is some clarification if this statement is in fact true, if not i will go on with my project happily using reflection snippets. If it is true i then would be looking for a better alternative. It is much better practice in my opinion to use an explicit dispatch. But you do whatever you want. If it becomes a performance problem for you and you're on a production site, then we'll look at it. More broadly, we like to help newbies and folks with live production sites. But, we also expect that newbies will bring us real issues that they themselves are facing, not premature optimizations. We have limited time to help people and wasting (and this thread has crossed seriously into time-wasting land) time with stuff that doesn't really impact you means that (1) you will get a lot less attention in the future (think the boy who cried wolf) and (2) it lowers the quality of discussion for the rest of the folks on the list. I really don't get your response, as Hugo just asked about a statement on the wikipage, which very clearly says that using reflection snippets brings a performance hit and is discouraged to be used in production. Now, it may very well be that this statement shouldn't be there as it's not true - which is your opinion I think. Maybe it would be better to write something like: If you are experiencing performance problems because of too many reflection calls, the cause may be using reflection snippets. Consider using dispatch snippets. But why do you say to new users who just ask about statements from the wiki that their posts are time-wasting and that they can get less attention in the future I really don't understand. Peace :) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Deploying Lift app
I can't quite figure out how to deploy my lift app and was hoping one of you could point me in the right direction. For fun i uploaded my entire project (uncompiled) to the server and ran mvn jetty:run - this worked fine but as soon as i killed my ssh connection the jetty server stopped. I think it should be enough to run mvn jetty:run in the background. My start-server.sh script: #!/bin/bash mvn jetty:run log.out 21 (puts all logs in log.out for further inspection) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Snippet with no reflection an no massive case statement
Please read the entire thread and the other threads that Hugo has started. Hugo is pushing on this issue (without any real basis, measurement, problems, statistics) and not letting it go. I've answered his question a number of times (using dispatch snippets is best practices [more from a code readability standpoint, but also there is a minor performance penalty]) and he keeps harping on the issue. I think that the statement on the wiki may sound too authoritative and that may be the source of misunderstanding - I'll edit the wiki to clear this up. I remember I've also wondered about this sentence when I was starting to get to know lift. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Comet shutdown?
As mentioned earlier, please try *lifespan* instead. def lifespan: Box[TimeSpan] is what you probably want. Ah :D I thought you were correcting the type parameter in David's email, didn't notice the function name. Thanks a lot! :) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Error messages are not displayed - 2.0-M1
Hello, If you are using an Ajax form lift:msgs showAll=true/ did not show the messages associated with ID's ... messages coming from FieldError. This is a defect I fixed about a week ago. Please use the latest lift build. Ah, I didn't realize that this ticket got closed. Anyway, I checked with snapshot and it works. Thanks Marius :) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Error messages are not displayed - 2.0-M1
Hello, are you submitting the form with ajax? If so, see this thread: http://groups.google.com/group/liftweb/browse_thread/thread/e25d86a24a5266a2/9fdcf9f2ce022618 In short, check if doing: xs.map {i = S.error(i.msg) }; instead of: S.error(xs); works. Hi Jeppe, lift:Msgs showAll=true does not work. Always the same result. If the form does not contain errors the data are saved well and the browser display S.notice(saved) correctly. The S.error method returns a List[FieldError]. I receive a List with the format of List(Full(tablename_field) : message) this is a field of my database class: [code] object description extends MappedTextarea(this, 255) { override def displayName = Description override def validations = valMinLen(1, S.??(description must not be empty)) _ :: super.validations } [/code] thanks, wibble On Feb 6, 12:19 pm, Jeppe Nejsum Madsen je...@ingolfs.dk wrote: wibblecp wibbl...@gmail.com writes: it does not work even in the case of a single error on the form. the result is always a List(Full(entries_code) : Description must not be empty) Try adding showAll: lift:Msgs showAll=true But default, Msgs doesnøt show field-level errors /Jeppe -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] ProtoUser i18n
Hmm right, although e.g. password already exists as a key and it wouldn't be good to duplicate it as Password. Same about Email. On Feb 2, 2010, at 1:08 PM, Jeppe Nejsum Madsen wrote: Adam Warski a...@warski.org writes: We'll accept a patch for this issue. Here's the patch. Note that this will break all existing translations. While having a complete list of keys that can be translated is great, I don't really think there's a reason to change the keys. E.g. First\ Name is, while maybe not common, a valid key. /Jeppe -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] ProtoUser i18n
Hmm right, although e.g. password already exists as a key and it wouldn't be good to duplicate it as Password. Same about Email. Good point. Also, the spaces in keys seem to confuse people, so maybe this is breakage that is worth it I guess I'll leave the decision up to David ;) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] ProtoUser i18n
Sure: (a) http://github.com/dpp/liftweb/issues/issue/320 (b) http://gist.github.com/293435 I've also updated the wiki. On Feb 2, 2010, at 8:10 PM, Indrajit Raychaudhuri wrote: Adam, can you please (a) open a ticket and (b) create a gist (http://gist.github.com/) of the patch and refer to it from the ticket? We'll take it up from there. Tim, +1 on not having spaces in properties. Cheers, Indrajit On 02/02/10 10:41 PM, Timothy Perrett wrote: Sure - one of us will take this up... its minor. I propose we agree a policy, and use that going forward... should keys have spaces? no would be my default response... (i tend to separate with full stops) if thats so, lets just clear that out now, and do a breaking changes ann. Cheers, Tim On 2 Feb 2010, at 17:06, David Pollak wrote: I'm okay with breakage here. Jeppe, Indrajit, or Tim, can you guys handle this issue going forward (making sure the patch is good, putting it on a branch, opening a ticket, putting it on review board, and sending out any breaking changes email)? -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] ProtoUser i18n
Hello, I'm using ProtoUser and all strings in the user menu, login, forgot password forms are localized except the Sign Up and Edit user forms. The problem is that in ProtoUser, the display names are defined as: def firstNameDisplayName = ??(First Name) instead using e.g. first.name. Sometimes the strings are in the resource bundles already (e.g. email, password), so it's just a matter of changing the keys. For others, new keys have to be added. I'd be of course happy to provide a patch with english polish translations, but I read that you don't accept patches for some reason (although I can transfer all the IP for this big change to you ;) ). Another thing is could the localForm method in ProtoUser stop being private (now it's private def localForm, line 628)? I just wanted to change the edit/signup forms decoration and for now had to copy the localForm into my code. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] NPE in MappedTextarea
Hello, if the value of a MappedTextarea field is null, an NPE is thrown. The problem is in the _toForm method. For example in MappedString, the method does: value={is match {case null = case s = s.toString}} while in MappedTextarea, the value is simply {is.toString}, which causes the NPE. So the fixed version should be, at line 29 of MappedTextarea: override def _toForm: Box[Elem] = { S.fmapFunc({s: List[String] = this.setFromAny(s)}){funcName = Full(textarea name={funcName} rows={textareaRows.toString} cols={textareaCols.toString} id={fieldId}{is match {case null = case s = s.toString}}/textarea)} } -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Passing attributes to bound elements
Hello, This was considered later on a defect, and not a feature. To preserve markup attributes in your bind use -% instead of - thanks, although the -% is missing support for the .toForm, as it returns a Box[NodeSeq]. And for % you need an Elem. Any ideas how to deal with that? :) What are you applying toForm to? In this case it is a MappedDate. But I've worked around the problem using jquery (all I wanted to do is add the datepicker anyway): I can wrap the bound element using a span class=datePicker.../span, and then lookup all elements with that class, and for each get the child and apply the datepicker creation. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Passing attributes to bound elements
Hello, This was considered later on a defect, and not a feature. To preserve markup attributes in your bind use -% instead of - thanks, although the -% is missing support for the .toForm, as it returns a Box[NodeSeq]. And for % you need an Elem. Any ideas how to deal with that? :) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Lift + UTF-8
Hello, maybe you have some ideas. I'm trying to make my lift app able to store polish characters, and I'm slowly running out of ideas. I think it's something with mapper configuration, but I'm not sure. When I submit a form with an ą character, I get the following exception: Message: java.sql.SQLException: Incorrect string value: '\xC4\x85' for column 'title' at row 1 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) What I did so far: - the mysql table encoding is utf-8 - the connection string contains useUnicode=truecharacterEncoding=UTF-8 - LiftRules.early.append(_.setCharacterEncoding(UTF-8)) When the String is set on the model field it still is correct, so something happens when trying to persist the value. Is there a way in lift to configure jdbc so that it accepts utf-8 characters? Or am I missing something else? -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Lift + UTF-8
Heh, sorry, I knew the moment I write a post here I'll find the answer ;) Forgot that when converting a table in mysql you not only need to set the character encoding for the table but also for the individual columns. Sorry again for the spam. On Jan 29, 2010, at 3:01 PM, Adam Warski wrote: Hello, maybe you have some ideas. I'm trying to make my lift app able to store polish characters, and I'm slowly running out of ideas. I think it's something with mapper configuration, but I'm not sure. When I submit a form with an ą character, I get the following exception: Message: java.sql.SQLException: Incorrect string value: '\xC4\x85' for column 'title' at row 1 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) What I did so far: - the mysql table encoding is utf-8 - the connection string contains useUnicode=truecharacterEncoding=UTF-8 - LiftRules.early.append(_.setCharacterEncoding(UTF-8)) When the String is set on the model field it still is correct, so something happens when trying to persist the value. Is there a way in lift to configure jdbc so that it accepts utf-8 characters? Or am I missing something else? -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Lift logging improvements
Also another logging-related problem that I sometimes have is that if an ajax call throws an exception, nothing is shown in the container logs. I can only see the stacktrace when I open up the ajax call's response in firebug. This sometimes takes time to figure out as at first it seems that clicking the button/link does nothing :). Although I haven't yet searched Boot to see where I can set ajax logging, I think that by default such exceptions should be logged. Adam On Jan 28, 2010, at 12:19 PM, Jeppe Nejsum Madsen wrote: aw anth...@whitford.com writes: One thing that bugs me is how all the logging comes from one logger: lift [Slf4jLogger.scala:110] As a result, you don't have the granularity to adjust just org.liftweb.http or org.liftweb.mapper, for example. Indeed. That is one of the things I would try to remedy http://github.com/dpp/liftweb/issues/#issue/310 I liked your suggestion about adding a Logging trait: http://groups.google.com/group/liftweb/browse_thread/thread/6aa012b673946242/b51747a0009ebae2?lnk=gstq=LOGGER#b51747a0009ebae2I'm thinking this would be a nice addition to the framework. I agree. I've created a ticket to track these changes: http://github.com/dpp/liftweb/issues/#issue/309 /Jeppe -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Loc hidden if type parameter is Unit and default value is Empty
Hello, I just found something very strange. I have my own loc, which extends Loc[Unit]. If the default value is empty (def defaultValue = Empty), then the loc won't be shown in the menu (I don't have any LocParams). If the default value is Full(()), then it is shown. I have other locs with other type params (that is, not Unit), where the default value is Empty, and they are shown normally. Is this a bug, or expected behaviour for some reason? -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Passing attributes to bound elements
When trying to use datepicker on a form, I found a post (by Derek Chen-Becker) from august which says: OK, the key there is the entrydate id. If you look at src/main/webapp/index.html, you'll see the markup in the Add Entry form: tde:dateOf e:id=entrydate e:maxlength=10//td That e:id attribute gets merged so that the resulting element has the attribute id=entrydate set (likewise for maxlength). This is a convenient way of setting attributes on templates that will be bound in your snippets. And I wanted to use this way of setting attributes on elements, but it doesn't seem to work - no attributes get rendered on the resulting element. Is this still supported? (the only difference from the example is that I don't use e:id but my own prefix which I then bind to in my snippet) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Creating a path from a Loc
Hello, If you need a String: (for { loc - SiteMap.findLoc(Login) path - loc.createDefaultPath } yield path.text) openOr / right, I could just convert it to text. That works, thanks :). -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] What is purpose of RequestVar/StatefulSnipplet for forms?
Hello, What's the purpose of RequestVars and StatefulSnippet? I thought the values were retained anyway through POST. That is, on submit, the functions desc = _ and amount = _ were executed and the so the state was kept... Are those functions only executed after the bind is complete? There must be something I'm missing here. The functions are called after form submission, and the variable desc and amount will be updated. However those variables will belong to the original method call. So when the page is re-rendered (e.g. because of validation errors), the add method will be called again, and fresh variables will be created. So the values won't be retained. If you want to keep the values between updating and re-rendering, you need something more global, like a RequestVar or a StatefulSnippet. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Creating a path from a Loc
Hello, Instead of building your Loc inline in the SiteMap declaration and using findLoc, simply declare the loc as a val (with the appropriate type parameter) in Boot or a similar object of your choosing. yes, that looks quite nice, although I'm just using User.sitemap for now :). But looking at MetaMegaProtoUser trait I now see that there's for example a loginPath val which I can simply use instead of lookuing up the loc. As well as some other useful functions :) -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Creating a path from a Loc
Hello, I'm having some trouble generating a link basing on a Loc. My original use-case is to redirect the user to a login page if the user is not logged in. I found a wiki on this and it says there to simply redirect to /user_mgt/login, however I think it would be much nicer if I could generate the link basing on looking up the right Loc. However having the Loc I can only generate a NodeSeq, not a plain String. So the solution would be to add a method into the Loc trait parallel to this one: def createDefaultLink: Option[NodeSeq] = currentValue.flatMap(p = link.createLink(p)).toOption which would be: def createDefaultPath: Option[String] = currentValue.flatMap(p = link.createPath(p)).toOption (btw., why is it Option here, not Box?) Then generating a link to the login page would simply be: SiteMap.findLoc(Login).open_!.createDefaultPath -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Creating a path from a Loc
Hello, For this you can use loc.link.createPath. I use something similar in my codebase. This has a little cruft you may not be precisely interested in, but if you look at the link and flink methods, you should be able to get an idea of how to use the Loc.Link: I'm using Link in a similar way to, but here I can't use createPath, as SiteMap.findLoc(...) returns a Loc[_], so the type parameter is unknown, so without some casts I won't be able to pass the parameter. I tried: val loc = SiteMap.findLoc(Login).open_! val link = loc.link.createPath(loc.currentValue.open_!) but unfortunately the compiler doesn't seem to recognize the fact that the type parameter for loc is the same as the one returned for loc.currentValue. -- Adam Warski http://www.warski.org http://www.softwaremill.eu -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] HTML table links
Hello, table cellpadding=7px title=User summary thFirst Name/th thLast Name/th thHours Summary/th thWage/th lift:Users.list tr onmouseover=this.bgColor='#ee'; onmouseout=this.bgColor='#FF'; onclick=window.location ='URL_TO_USER_DETAILS'; tdu:fname //td tdu:lname //td tdu:hours //td tdu:money //td /tr /lift:Users.list /table What I want to achieve is that users clicks on table row and gets redirected to details about selected row (user in this case). I would like to implement this in View First pattern so i thought about replacing 'onclick' attribute inside Users.list method but I don't know the easy way to do this. The naive way would be using regular expressions, but i've got feeling that i'm reinventing wheel here. Please help. There are several ways to do it. I think the easiest one is to bind the view link to a SHtml.link, something like: users.flatMap { user = bind(..., ..., view - link(view.html, () = SelectedUser(user), Text(View user)) } where view.html is a template where you can view the user, SelectedUser is a RequestVar that holds the selection after you've clicked. You will also need to add the view.html to your sitemap. If you want a persistent URL for viewing users, you can add a rewrite rule. The use-case you are writing about is quite well described in the lift book (available in pdf for free), so I would also recommend looking there. -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: HTML table links
Hello, Could you please point me, I can't find it. if you mean the lift book, it's here: http://groups.google.com/group/the-lift-book -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax forms and (multiple) submit buttons
Hello, Right ... and it's not even a hack ... css is the right way of building layout not really the html. Putting buttons in the form ar giving this perception in the page doesn't mean that the button has to be physically in the form element (at least that's the way I see it.). actually I think I'll take back the doable with CSS as it's quite easy for an add element button, but per-element operations, like delete, move up, move down would take really some more time to layout properly, if they were placed outside the form :). But as I said, I'll make the whole form AJAX :). -- Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax forms and (multiple) submit buttons
Hello, Hmm yes I wondered if the order in which the functions are bound is significant, but my experiments showed that it's not simply a first bound, first called principle. So I don't quite get it yet why it doesn't work. We rely on JQuery (or other underlying library) to send the actual ajax request. We feed in the correct sequence but if your button is in the middle of the form (as fields were added after the button's location in the form) the sequence of the function id-s is not sent right via ajax even if onclick for the ajax button we first serialize the for and then add the function ID of the ajax button. Personally I don't see why this is an impediment ah, clear now. Thanks a lot for the explanation. This is a small impediment if the button logically belongs inside the form (if I want the user to see the button inside the form), but then, as I wrote, I can use css to correctly position it, although I would consider it a small hack :) -- Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax forms and (multiple) submit buttons
Hello, I tried the trunk version and again it almost works :) 1. the RequestVars aren't preserved for the ajax request. I think this can be fixed by replacing in SHtml:692 the NFuncHolder with a call to contextFuncBuilder, so the method would look like this: def doit = makeFormElementWithName(submit, contextFuncBuilder(func), attrs: _*){ case (funcName, elem) = elem % new UnprefixedAttribute(value, Text(value), Null) % (onclick - (liftAjax.lift_uriSuffix = '+funcName+=_'; return true;)) } I tested it on my example application (http://github.com/adamw/lift-ajax-submit-test) and it works. 2. The button will work only with full ajax-forms right? So forms wrapped with ajaxForm(...)? My initial use-case was for adding some ajax buttons to normal forms (submitted with a normal http request), but I guess I can make the whole form submitted with ajax. Thanks! Adam Most likely I'll commit it today in master as it was approved by review board. Br's, Marius On Jan 14, 9:53 am, Adam Warski a...@warski.org wrote: I would of course be very +1 to include the ajaxSubmit :). Thanks for the work. This looks a bit different to the button I tried before, maybe you have a patch so that I can try it out on the test app? Adam On Jan 12, 2010, at 8:39 PM, Marius wrote: Dear all, Recently (and not only) there have been discussions about ajax forms and their submit Scala functions not being called and that's because JQuery's form serialization doesn't serialize the input submits (for pertinent reasons). The workaround is as you know to use hidden fields. Adam also wanted an ajax form with multiple submit buttons taking different actions depending on which button is being called. This is also *doable* using hidden fields but not quite from elegant. I've experimented a way to allow ajax form submission but after all form field functions are being called your own ajax Scala function is being called (with no hidden fields). the idea is this: 1. I added an SHtml.ajaxSubmit which has the same signature with SHtml.submit 2. At js level I added a liftAjax.lift_uriSuffix 3. When clicking the ajaxSubmit button we set the liftAjax.lift_uriSuffix with the function name value. This is the function name of your scala function. Hence your scala function for ajaxSubmit will be called after form field functions are called. In short we piggy back the Scala function info on top of the serialized form info. I tested it and it works just fine for me: Using it looks something like like: ajaxForm(bind(hello, xhtml, field1 - text(, (s) = {println(field1 = + s)}), field2 - text(, (s) = {println(field2 = + s)}), field3 - text(, (s) = {println(field3 = + s)}), submit - ajaxSubmit(Press me, () = { println(my ajax func called.) Noop })) ... you got the idea. This of course allows putting virtually any number of ajax submit buttons and the right function will be called on server side. I'm thinking to add this to Lift but first I'd like to know your thoughts. Br's, Marius -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax forms and (multiple) submit buttons
Hello, Oh yeah contextFuncBuider ... good catch. I'll update today. thanks :) 2. The button will work only with full ajax-forms right? So forms wrapped with ajaxForm(...)? My initial use-case was for adding some ajax buttons to normal forms (submitted with a normal http request), but I guess I can make the whole form submitted with ajax. Yes it is meant to work for ajaxForm. But for normal forms you can use submitAjaxForm you could use the ajaxButton I sent on a different thread. Not sure what the issue was with that as in my tests it worked fine. well I guess you were just lucky because with the modified ajax button some form fields where update before, and some after the associated function was called. So in your tests all form fields feel into the before category. But in my test case on github some field elements are updated after the function, so they loose their value (it's very simple btw., just one form with a list of elements). -- Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax forms and (multiple) submit buttons
I kinda doubt that as I tested with a bunch of form fields. In the ajax request the function ID of the ajax function was always the last in the parameters and functions are evaluated in canonical order (for the same owner). But I think you sent me your source code location and I need to look what's in there this weekend. I Hope your code that works as you described is still there :) Yep, it's still there: http://github.com/adamw/lift-ajax-submit-test Just run it, add one element, fill in the two input fields, and click add again, you should see the input disappearing. Thanks a lot :) -- Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
Hello, the problem is that some form elements are updated, then the function is called, and then the rest of the form elements are updated. My code is more or less something like this: def editElement(elementTemplate: NodeSeq): NodeSeq = { container.elements.flatMap { element: Element = bind(element, elementTemplate, name - { println(bind element name + element.name); SHtml.text(element.name.is, (s: String) = {println(set element name + s); element.name(s); }) } ) } } bind(cont, containerTemplate, name - { println(bind container name + conf.name); SHtml.text(cont.name.is, (s: String) = {println(set container name + s); cont.name(s); }) }, elements - editElement _, addElement - ajaxButton(Text(Add), edit_formid, () = { println(executing function); cont.addElement; reDraw }) ) And the output, when I submit a form where 1 element is already added is: 09:04:23,450 INFO [STDOUT] set container name a 09:04:23,474 INFO [STDOUT] executing function 09:04:23,474 INFO [STDOUT] bind container name a 09:04:23,475 INFO [STDOUT] bind element name 0 09:04:23,476 INFO [STDOUT] bind element name 1 09:04:23,478 INFO [STDOUT] set element name 0a So as you can see first cont.name is set, then the button function is executed, and later the element.names are set. I can try creating a small lift app which would demo this if you'd like. Also, I'm using 1.1-M8. Maybe I should try some newer version? (2.0-SNAPSHOT? 1.1-SNAPSHOT?) Adam On Jan 12, 2010, at 6:03 PM, Marius wrote: I must have misread your post. I did test the ajaxButton above (with your corrections) and the behaviour is correct. Form field functions are invoked first and then your ajax function provided to ajaxButton. Thus this is a good way for adding submit functions for ajax form without the need of using hidden fields and I'll promote this for addition in Shtml (probably with slight modifications). I think the method name should be ajaxSubmit I don't quite get why you're saying this is a problem. What does step 3 needs to accomplish? . all form fields functions are called (except if you have a Shtml.submit because form serialization does not include submits). Then you function is invoked and the response is sent to client. You mentioned that you just need to add multiple buttons for a ajax form ... this version of ajaxButton does just that. Can you please clarify your used case for for for those 3 steps? ... Br's, Marius On Jan 12, 4:20 pm, Adam Warski a...@warski.org wrote: Hello, this *almost* works :). I modified your code a bit and now I have: def ajaxButton(text: NodeSeq, formId: String, func: () = JsCmd, attrs: (String, String)*): Elem = { attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name = button onclick={makeAjaxCall(JsRaw( LiftRules.jsArtifacts.serialize(formId).toJsCmd + + + Str( + name + =true).toJsCmd)).toJsCmd + ; return false;}{text}/button))(_ % _) } Now the form submits and the right function is executed on the server, and the form is redrawn in the browser. However, the problem is in the ordering of operations. The sequence basically is: (1) update some elements of the form (2) execute the function (3) update the rest of the elements of the form The problem of course is that (2) returns the new content of the form (a SetHtml JsCmd), generated basing on state without all fields updated. I don't quite yet get the rule deciding which fields get updated before calling the function, and which after. One thing I noticed is that if I move the field that is bound first (in bind(...)) to be the last field, it gets moved from group (1) to (3). Also, I thought that maybe the ordering of POST values matters, but swapping Str( + name + =true).toJsCmd and LiftRules.jsArtifacts.serialize(formId).toJsCmd doesn't have any effect. I tried the form many times and always get the same behaviour, so the (1) vs. (3) division seems to be deterministic :) Adam On Jan 11, 2010, at 10:58 PM, Marius wrote: Adam I was thinking of a slightly different approach that does not involve hidden fields: Say you have your current form with SHtml.text, checkboxes or whatever have you: then your ajax buttons (outside the form) like: def ajaxButton(text: NodeSeq, formId: String, func: () = JsCmd, attrs: (String, String)*): Elem = { attrs.foldLeft(fmapFunc(contextFuncBuilder(SFuncHolder(func))) (name = button onclick={makeAjaxCall(JsRaw (LiftRules.jsArtifacts.serialize(formId) + + name.encJs + =_)).toJsCmd + ; return false;}{text}/button))(_ % _) } I haven't tested though but you get the idea ... When we do the ajax call, we serialize the form and add the name parameter as well. This will cause your field functions to be called, and at the end you
Re: [Lift] Re: Ajax button + submitting a form
Hello, Yes please a small app would be best. Please use 2.0-SNAPSHOT. Here it is: http://github.com/adamw/lift-ajax-submit-test/ Steps to reproduce: 1. checkout from git :) 2. run mvn jetty:run 3. go to http://localhost:8080 4. click add once 5. fill in the two fields with some values e.g. container, room 6. click add again 7. the container value will stay, while the room value will disappear. In the logs, you can see: set container name cont executing funtion bind container name cont bind room name bind room name set room name room Also please see this thread: http://groups.google.com/group/liftweb/browse_thread/thread/75750c42ec3a2d7d?hl=en# Yeah, I saw it, as far as I understand the ajaxSubmit is more or less the same as the ajaxButton you did (and I corrected)? Thanks, Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
Also, interestingly, if you change the order of binding from: bind(cont, containerTemplate, name - { println(bind container name + cont.name); SHtml.text(cont.name, (s: String) = {println(set container name + s); cont.name = s; }) }, rooms - editRoom _, addRoom - ajaxButton(Text(Add), cont_edit, () = { println(executing funtion); cont.rooms += new Room; reDraw }) ) to: bind(cont, containerTemplate, rooms - editRoom _, addRoom - ajaxButton(Text(Add), cont_edit, () = { println(executing funtion); cont.rooms += new Room; reDraw }), name - { println(bind container name + cont.name); SHtml.text(cont.name, (s: String) = {println(set container name + s); cont.name = s; }) } ) then the container name is also lost on submit. The log output is then: executing funtion bind container name bind room name bind room name set container name container set room name room Adam On Jan 13, 2010, at 10:13 AM, Adam Warski wrote: Hello, Yes please a small app would be best. Please use 2.0-SNAPSHOT. Here it is: http://github.com/adamw/lift-ajax-submit-test/ Steps to reproduce: 1. checkout from git :) 2. run mvn jetty:run 3. go to http://localhost:8080 4. click add once 5. fill in the two fields with some values e.g. container, room 6. click add again 7. the container value will stay, while the room value will disappear. In the logs, you can see: set container name cont executing funtion bind container name cont bind room name bind room name set room name room Also please see this thread: http://groups.google.com/group/liftweb/browse_thread/thread/75750c42ec3a2d7d?hl=en# Yeah, I saw it, as far as I understand the ajaxSubmit is more or less the same as the ajaxButton you did (and I corrected)? Thanks, Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Ajax forms and (multiple) submit buttons
I would of course be very +1 to include the ajaxSubmit :). Thanks for the work. This looks a bit different to the button I tried before, maybe you have a patch so that I can try it out on the test app? Adam On Jan 12, 2010, at 8:39 PM, Marius wrote: Dear all, Recently (and not only) there have been discussions about ajax forms and their submit Scala functions not being called and that's because JQuery's form serialization doesn't serialize the input submits (for pertinent reasons). The workaround is as you know to use hidden fields. Adam also wanted an ajax form with multiple submit buttons taking different actions depending on which button is being called. This is also *doable* using hidden fields but not quite from elegant. I've experimented a way to allow ajax form submission but after all form field functions are being called your own ajax Scala function is being called (with no hidden fields). the idea is this: 1. I added an SHtml.ajaxSubmit which has the same signature with SHtml.submit 2. At js level I added a liftAjax.lift_uriSuffix 3. When clicking the ajaxSubmit button we set the liftAjax.lift_uriSuffix with the function name value. This is the function name of your scala function. Hence your scala function for ajaxSubmit will be called after form field functions are called. In short we piggy back the Scala function info on top of the serialized form info. I tested it and it works just fine for me: Using it looks something like like: ajaxForm(bind(hello, xhtml, field1 - text(, (s) = {println(field1 = + s)}), field2 - text(, (s) = {println(field2 = + s)}), field3 - text(, (s) = {println(field3 = + s)}), submit - ajaxSubmit(Press me, () = { println(my ajax func called.) Noop })) ... you got the idea. This of course allows putting virtually any number of ajax submit buttons and the right function will be called on server side. I'm thinking to add this to Lift but first I'd like to know your thoughts. Br's, Marius -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
Hello, this *almost* works :). I modified your code a bit and now I have: def ajaxButton(text: NodeSeq, formId: String, func: () = JsCmd, attrs: (String, String)*): Elem = { attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name = button onclick={makeAjaxCall(JsRaw( LiftRules.jsArtifacts.serialize(formId).toJsCmd + + + Str( + name + =true).toJsCmd)).toJsCmd + ; return false;}{text}/button))(_ % _) } Now the form submits and the right function is executed on the server, and the form is redrawn in the browser. However, the problem is in the ordering of operations. The sequence basically is: (1) update some elements of the form (2) execute the function (3) update the rest of the elements of the form The problem of course is that (2) returns the new content of the form (a SetHtml JsCmd), generated basing on state without all fields updated. I don't quite yet get the rule deciding which fields get updated before calling the function, and which after. One thing I noticed is that if I move the field that is bound first (in bind(...)) to be the last field, it gets moved from group (1) to (3). Also, I thought that maybe the ordering of POST values matters, but swapping Str( + name + =true).toJsCmd and LiftRules.jsArtifacts.serialize(formId).toJsCmd doesn't have any effect. I tried the form many times and always get the same behaviour, so the (1) vs. (3) division seems to be deterministic :) Adam On Jan 11, 2010, at 10:58 PM, Marius wrote: Adam I was thinking of a slightly different approach that does not involve hidden fields: Say you have your current form with SHtml.text, checkboxes or whatever have you: then your ajax buttons (outside the form) like: def ajaxButton(text: NodeSeq, formId: String, func: () = JsCmd, attrs: (String, String)*): Elem = { attrs.foldLeft(fmapFunc(contextFuncBuilder(SFuncHolder(func))) (name = button onclick={makeAjaxCall(JsRaw (LiftRules.jsArtifacts.serialize(formId) + + name.encJs + =_)).toJsCmd + ; return false;}{text}/button))(_ % _) } I haven't tested though but you get the idea ... When we do the ajax call, we serialize the form and add the name parameter as well. This will cause your field functions to be called, and at the end you ajaxButton function to be called. Inside func function your RequestVar should be preserved due to contextFuncBuilde call. Please let me know if this works. If it does we should probably add it to SHtml. Br's, Marius On Jan 11, 10:54 pm, Adam Warski a...@warski.org wrote: Hello, trying the solution a bit more I came into another problem which I can't solve elegantly. The solution below works nicely for an add button, but a delete button causes more problems: the problem is that with delete, you must know which element should get deleted. In a no-ajax solution, it is enough to do: elements.flatMap { element: Element = bind(element, element Template, name - element.name.toForm, delete - submit(Delete, () = { elements -= element }) ) } which is very nice and easy, as the element to delete gets captured in a closure. But with ajax, and a hidden field used to hold the name of the operation to dispatch, this gets pretty complex: I now need to somehow encode the element to delete (or create a map from some unique identifier to closures which hold the delete methods), so that I can set this as a value of the hidden field. Then in the function passed to SHtml.hidden, I need to decode it back to find the right element. Isn't it a bit of what Lift already does when creating forms? But I still have the feeling that maybe I'm approaching the whole problem from the wrong end, after all, I just want to create an ajax-enabled list of input fields with add and delete operations :) Adam On Jan 11, 1:09 pm, Adam Warski a...@warski.org wrote: Hello, this almost works :). Right now in my form I have a hidden element where the type of the operation to execute will be set: input type=hidden id=operation_id name=operation_id value= / (the name is needed for jquery to set the value, and the id so that I can later read the value using S). I bind the button as following: addElement - button onclick={((JqId(Str(operation_id)) JqAttr(value, Str(add))) SHtml.submitAjaxForm(elements_edit)).toJsCmd+ return false;}{Text(Add element)}/button, and add a hidden field to the whole form to do the processing: bind( ... ) ++ SHtml.hidden(() = { val operationId = S.param(operation_id) operationId.map { opId = opId match { case add = elements += new Element case _ = println(Unknown operation: + opId) } } reDraw }) where elements is a RequestVar object. However for some reason, when I click the button, in the callback I get a new elements RequestVar (so it's
Re: [Lift] Re: Ajax button + submitting a form
Hello, this almost works :). Right now in my form I have a hidden element where the type of the operation to execute will be set: input type=hidden id=operation_id name=operation_id value= / (the name is needed for jquery to set the value, and the id so that I can later read the value using S). I bind the button as following: addElement - button onclick={((JqId(Str(operation_id)) JqAttr(value, Str(add))) SHtml.submitAjaxForm(elements_edit)).toJsCmd+ return false;}{Text(Add element)}/button, and add a hidden field to the whole form to do the processing: bind( ... ) ++ SHtml.hidden(() = { val operationId = S.param(operation_id) operationId.map { opId = opId match { case add = elements += new Element case _ = println(Unknown operation: + opId) } } reDraw }) where elements is a RequestVar object. However for some reason, when I click the button, in the callback I get a new elements RequestVar (so it's initialized to an initial value) and moreover, nothing gets redrawn on the page. What is also quite weird is that the RequestVar is re-initialized, but the snippet instance stays the same. Any ideas? :) I thought that my use-case would be quite common in lift: I just want to add a couple of buttons to my form which execute different actions. Thanks for the help! Adam On Jan 10, 2010, at 6:03 PM, Marius wrote: Sorry I think the syntax would be (I haven't tested it though): button onclick={((JqId(hidden_field_id) JqAttr(value, add)) SHtml.submitAjaxForm(form_ID)).toJsCmd}add/button button onclick={((JqId(hidden_field_id) JqAttr(value, edit)) SHtml.submitAjaxForm(form_ID)).toJsCmd}edit/button button onclick={((JqId(hidden_field_id) JqAttr(value, delete)) SHtml.submitAjaxForm(form_ID)).toJsCmd}delete/button Br's, Marius On Jan 10, 6:58 pm, Marius marius.dan...@gmail.com wrote: On Jan 10, 5:20 pm, Adam Warski a...@warski.org wrote: Hello, ajaxButton(Press me would ya'?, SHtml.submitAjaxForm (form_ID).toJsCmd, (some) = { do your stuff here }) Looking at the source code I think this might work, but I'm having trouble constructing the correct expression to pass to ajaxButton. The method signature requires a Call instance, and SHtml.submitAjaxForm results in a command (JsCmd). Is it possible to somehow combine the two? I was referring to this signature: def ajaxButton(text: NodeSeq, jsExp: JsExp, func: String = JsCmd, attrs: (String, String)*): Elem and not def ajaxButton(text: NodeSeq, jsFunc: Call, func: () = JsCmd, attrs: (String, String)*): Elem jsExp will be called before sending the actual ajax. But this may be a bit problematic if your jsExp sends the ajaxForm the ajax request is processed asynchronously at js level meaning the the button ajax request may be send before the actual ajax form processing is done. I'm not sure if this fits your needs Or maybe there is some other, lift-idomatic way to solve my problem? I want to create a form with a list of elements, with three ajax buttons: add, remove and save (adding/removing a row and persisting the list) The first solution I described involving hidden fields will definitely work. I don't think you need to do 2 ajax calls (one for the form and one for the button) but piggy back the button information into a hidden field and only submit the form: Perhaps something like: button onclick={(JqId(hidden_field_id) JqAttr(value, add)) + + SHtml.submitAjaxForm(form_ID).toJsCmd}blah/button By the way, I think there's a small inconsistency; there are 7 overloaded variants for ajaxButton: ajaxButton(text: NodeSeq, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: String, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: NodeSeq, jsFunc: Call, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: String, jsFunc: Call, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: NodeSeq, jsExp: JsExp, func: String = JsCmd, attrs: (String, String)*): Elem and the last one doesn't have a text: String counterpart. Also the javadoc for the last variant is missing information on what's jsExp and what's the argument passed to func. My guess would be that jsExp is evaluated and the result passed to func on the server? Yes jsExp is being evaluated and its result is being sent to server. Please open a defect for this inconsistency. -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift
Re: [Lift] Re: Ajax button + submitting a form
Hello, However for some reason, when I click the button, in the callback I get a new elements RequestVar (so it's initialized to an initial value) and moreover, nothing gets redrawn on the page. What is also quite weird is that the RequestVar is re-initialized, but the snippet instance stays the same. Any ideas? :) Yes I think so. You have a regular form with fields like: (SHtml.text. SHtml.hidden etc. right? RequestVars are kept around into a snapshot- restorer only for ajax functions (like for ajaxText etc) and not for regular fields forms. Thus in the Scala function of a SHtml.ajaxText you'll see the RequestVar set when the page was rendered because its state is preserved on purpose by lift. However for regular fields this is not happening. So there is a difference between an ajax-form and ajax fields. Even your form is sent via ajax, the fields are regular fields not ajax fields (... ajax fields do not even need to live inside a form). Therefore for your case the RequestVar's are not preserved and they are renewed when the request comes in. You can keep around that state using a SessionVar. Ah, clear now. And it even works, thanks a lot for the help! :) -- Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
Hello, I don't think you need a SessionVar. You can just capture the RequestVar's value in a local val and refer to that in the closure. Basically if I understand correctly, this is a typical scenario where you output a form and associate functions with its fields which are to be executed on the *next* request when it's submitted. That request will use a new snippet instance for its output, but first it executes your functions, which have captured references to whatever they refer to. yes, what I'm doing is I capture the value in a function and later in that function I update the request variable with the captured value so that the form is rendered correctly. -- Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
Hello, trying the solution a bit more I came into another problem which I can't solve elegantly. The solution below works nicely for an add button, but a delete button causes more problems: the problem is that with delete, you must know which element should get deleted. In a no-ajax solution, it is enough to do: elements.flatMap { element: Element = bind(element, element Template, name - element.name.toForm, delete - submit(Delete, () = { elements -= element }) ) } which is very nice and easy, as the element to delete gets captured in a closure. But with ajax, and a hidden field used to hold the name of the operation to dispatch, this gets pretty complex: I now need to somehow encode the element to delete (or create a map from some unique identifier to closures which hold the delete methods), so that I can set this as a value of the hidden field. Then in the function passed to SHtml.hidden, I need to decode it back to find the right element. Isn't it a bit of what Lift already does when creating forms? But I still have the feeling that maybe I'm approaching the whole problem from the wrong end, after all, I just want to create an ajax-enabled list of input fields with add and delete operations :) Adam On Jan 11, 1:09 pm, Adam Warski a...@warski.org wrote: Hello, this almost works :). Right now in my form I have a hidden element where the type of the operation to execute will be set: input type=hidden id=operation_id name=operation_id value= / (the name is needed for jquery to set the value, and the id so that I can later read the value using S). I bind the button as following: addElement - button onclick={((JqId(Str(operation_id)) JqAttr(value, Str(add))) SHtml.submitAjaxForm(elements_edit)).toJsCmd+ return false;}{Text(Add element)}/button, and add a hidden field to the whole form to do the processing: bind( ... ) ++ SHtml.hidden(() = { val operationId = S.param(operation_id) operationId.map { opId = opId match { case add = elements += new Element case _ = println(Unknown operation: + opId) } } reDraw }) where elements is a RequestVar object. However for some reason, when I click the button, in the callback I get a new elements RequestVar (so it's initialized to an initial value) and moreover, nothing gets redrawn on the page. What is also quite weird is that the RequestVar is re-initialized, but the snippet instance stays the same. Any ideas? :) Yes I think so. You have a regular form with fields like: (SHtml.text. SHtml.hidden etc. right? RequestVars are kept around into a snapshot- restorer only for ajax functions (like for ajaxText etc) and not for regular fields forms. Thus in the Scala function of a SHtml.ajaxText you'll see the RequestVar set when the page was rendered because its state is preserved on purpose by lift. However for regular fields this is not happening. So there is a difference between an ajax-form and ajax fields. Even your form is sent via ajax, the fields are regular fields not ajax fields (... ajax fields do not even need to live inside a form). Therefore for your case the RequestVar's are not preserved and they are renewed when the request comes in. You can keep around that state using a SessionVar. I thought that my use-case would be quite common in lift: I just want to add a couple of buttons to my form which execute different actions. Which is very easy to do. But your problem not is how you maintain your specific state (the elements) Thanks for the help! Adam On Jan 10, 2010, at 6:03 PM, Marius wrote: Sorry I think the syntax would be (I haven't tested it though): button onclick={((JqId(hidden_field_id) JqAttr(value, add)) SHtml.submitAjaxForm(form_ID)).toJsCmd}add/button button onclick={((JqId(hidden_field_id) JqAttr(value, edit)) SHtml.submitAjaxForm(form_ID)).toJsCmd}edit/button button onclick={((JqId(hidden_field_id) JqAttr(value, delete)) SHtml.submitAjaxForm(form_ID)).toJsCmd}delete/button Br's, Marius On Jan 10, 6:58 pm, Marius marius.dan...@gmail.com wrote: On Jan 10, 5:20 pm, Adam Warski a...@warski.org wrote: Hello, ajaxButton(Press me would ya'?, SHtml.submitAjaxForm (form_ID).toJsCmd, (some) = { do your stuff here }) Looking at the source code I think this might work, but I'm having trouble constructing the correct expression to pass to ajaxButton. The method signature requires a Call instance, and SHtml.submitAjaxForm results in a command (JsCmd). Is it possible to somehow combine the two? I was referring to this signature: def ajaxButton(text: NodeSeq, jsExp: JsExp, func: String = JsCmd, attrs: (String, String)*): Elem and not def ajaxButton(text: NodeSeq, jsFunc: Call, func: () = JsCmd, attrs: (String, String)*): Elem jsExp will be called before sending the actual ajax. But this may be a bit problematic
Re: [Lift] Re: Ajax button + submitting a form
Hello, thanks, but my use-case is a bit different. I want the whole form to be still submitted using a POST (the normal way), and only use ajax for a small fragment of the page (the element editor). So I can't use ajaxForm(...), as this would make all submit buttons use ajax. Adam On Jan 9, 2010, at 3:55 PM, greekscala wrote: Hello, I have a similar use case. For an AjaxForm you have to write: SHtml.ajaxForm( bind(mytags, xml, // binding to your tags ... submit - SHtml.submit(do it, save), ) ++ SHtml.hidden(save) ) You dont need to have a form element in your templates for this to work because ajaxForm will wrap the result of the bind method. For my listelements checkbox, I attach to the checkbox a function, that adds an Id and the checkbox value to a ListBuffer[(Boolean, String)]. (checked and not checked boxes are submittet) Then I filter the List for the selected values a do what I have to do with them. I the above code example, my save method does some db stuff and then returning a JsCmds.SetHtml(an html id, some html/snippet nodeseq) for a redraw. Hope this helps a little with best regards On 9 Jan., 10:48, Adam Warski a...@warski.org wrote: Hello, I have a regular form, which is submitted with a POST (no AJAX here yet). The form contains a list, to which you can add and remove elements using AJAX. So the add and remove buttons are: add - ajaxButton(Add element, () = { elements += new Element; reDraw }) The reDraw method is a SetHtml for the whole form. Now this almost works, with the exception that when I press the add button all other changes in the form are discarded, as the form is not submitted. So, when the button is pressed, I would need to submit the form using ajax and execute a given function on the server. In the archives I found SHtml.submitAjaxForm(formId) method, which I guess does what I need, but I don't know how to combine it with an ajaxButton? -- Thanks, Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
There is also a related problem: how can I have two ajax buttons on one form which submit the form and execute different functions on the server? Using the standard trick: SHtml.ajaxForm(bind(...) ++ SHtml.hidden(submitFunction)) won't work, as I want different functions executed for different buttons. Adam On Jan 10, 2010, at 10:42 AM, Adam Warski wrote: Hello, thanks, but my use-case is a bit different. I want the whole form to be still submitted using a POST (the normal way), and only use ajax for a small fragment of the page (the element editor). So I can't use ajaxForm(...), as this would make all submit buttons use ajax. Adam On Jan 9, 2010, at 3:55 PM, greekscala wrote: Hello, I have a similar use case. For an AjaxForm you have to write: SHtml.ajaxForm( bind(mytags, xml, // binding to your tags ... submit - SHtml.submit(do it, save), ) ++ SHtml.hidden(save) ) You dont need to have a form element in your templates for this to work because ajaxForm will wrap the result of the bind method. For my listelements checkbox, I attach to the checkbox a function, that adds an Id and the checkbox value to a ListBuffer[(Boolean, String)]. (checked and not checked boxes are submittet) Then I filter the List for the selected values a do what I have to do with them. I the above code example, my save method does some db stuff and then returning a JsCmds.SetHtml(an html id, some html/snippet nodeseq) for a redraw. Hope this helps a little with best regards On 9 Jan., 10:48, Adam Warski a...@warski.org wrote: Hello, I have a regular form, which is submitted with a POST (no AJAX here yet). The form contains a list, to which you can add and remove elements using AJAX. So the add and remove buttons are: add - ajaxButton(Add element, () = { elements += new Element; reDraw }) The reDraw method is a SetHtml for the whole form. Now this almost works, with the exception that when I press the add button all other changes in the form are discarded, as the form is not submitted. So, when the button is pressed, I would need to submit the form using ajax and execute a given function on the server. In the archives I found SHtml.submitAjaxForm(formId) method, which I guess does what I need, but I don't know how to combine it with an ajaxButton? -- Thanks, Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
right, I wrote about that in my original post, but how can I execute a button-specific method on the server-side? Thanks, Adam On Jan 10, 2010, at 12:15 PM, Marius wrote: The ajax buttons doesn't have to be inside the form if you use SHtml.submitAjaxForm(form_ID) button onclick={SHtml.submitAjaxForm(form_ID).toJsCmd}blah/button Br's, Marius On Jan 10, 1:08 pm, Adam Warski a...@warski.org wrote: There is also a related problem: how can I have two ajax buttons on one form which submit the form and execute different functions on the server? Using the standard trick: SHtml.ajaxForm(bind(...) ++ SHtml.hidden(submitFunction)) won't work, as I want different functions executed for different buttons. Adam On Jan 10, 2010, at 10:42 AM, Adam Warski wrote: Hello, thanks, but my use-case is a bit different. I want the whole form to be still submitted using a POST (the normal way), and only use ajax for a small fragment of the page (the element editor). So I can't use ajaxForm(...), as this would make all submit buttons use ajax. Adam On Jan 9, 2010, at 3:55 PM, greekscala wrote: Hello, I have a similar use case. For an AjaxForm you have to write: SHtml.ajaxForm( bind(mytags, xml, // binding to your tags ... submit - SHtml.submit(do it, save), ) ++ SHtml.hidden(save) ) You dont need to have a form element in your templates for this to work because ajaxForm will wrap the result of the bind method. For my listelements checkbox, I attach to the checkbox a function, that adds an Id and the checkbox value to a ListBuffer[(Boolean, String)]. (checked and not checked boxes are submittet) Then I filter the List for the selected values a do what I have to do with them. I the above code example, my save method does some db stuff and then returning a JsCmds.SetHtml(an html id, some html/snippet nodeseq) for a redraw. Hope this helps a little with best regards On 9 Jan., 10:48, Adam Warski a...@warski.org wrote: Hello, I have a regular form, which is submitted with a POST (no AJAX here yet). The form contains a list, to which you can add and remove elements using AJAX. So the add and remove buttons are: add - ajaxButton(Add element, () = { elements += new Element; reDraw }) The reDraw method is a SetHtml for the whole form. Now this almost works, with the exception that when I press the add button all other changes in the form are discarded, as the form is not submitted. So, when the button is pressed, I would need to submit the form using ajax and execute a given function on the server. In the archives I found SHtml.submitAjaxForm(formId) method, which I guess does what I need, but I don't know how to combine it with an ajaxButton? -- Thanks, Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Ajax button + submitting a form
Hello, ajaxButton(Press me would ya'?, SHtml.submitAjaxForm (form_ID).toJsCmd, (some) = { do your stuff here }) Looking at the source code I think this might work, but I'm having trouble constructing the correct expression to pass to ajaxButton. The method signature requires a Call instance, and SHtml.submitAjaxForm results in a command (JsCmd). Is it possible to somehow combine the two? Or maybe there is some other, lift-idomatic way to solve my problem? I want to create a form with a list of elements, with three ajax buttons: add, remove and save (adding/removing a row and persisting the list). By the way, I think there's a small inconsistency; there are 7 overloaded variants for ajaxButton: ajaxButton(text: NodeSeq, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: String, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: NodeSeq, jsFunc: Call, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: String, jsFunc: Call, func: () = JsCmd, attrs: (String, String)*): Elem ajaxButton(text: NodeSeq, jsExp: JsExp, func: String = JsCmd, attrs: (String, String)*): Elem and the last one doesn't have a text: String counterpart. Also the javadoc for the last variant is missing information on what's jsExp and what's the argument passed to func. My guess would be that jsExp is evaluated and the result passed to func on the server? -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Ajax button + submitting a form
Hello, I have a regular form, which is submitted with a POST (no AJAX here yet). The form contains a list, to which you can add and remove elements using AJAX. So the add and remove buttons are: add - ajaxButton(Add element, () = { elements += new Element; reDraw }) The reDraw method is a SetHtml for the whole form. Now this almost works, with the exception that when I press the add button all other changes in the form are discarded, as the form is not submitted. So, when the button is pressed, I would need to submit the form using ajax and execute a given function on the server. In the archives I found SHtml.submitAjaxForm(formId) method, which I guess does what I need, but I don't know how to combine it with an ajaxButton? -- Thanks, Adam-- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Errors not shown after AJAX form submit
Hello, I think the difference is in showAll scope. It was implemented for non Ajax context (just for msgs snippet) but it wasn't implemented for Ajax (as far as I can tell). Ajax notices (if there are any) are appended to user's JsCmd response. But this code has no idea about the showAll snippet attribute. Therefore ajax notices that are associates with an ID will not be shown in lift:Msgs showAll=true/ 's real estate. Please open a defect for this. I think I more or less understand :) Here's the defect: http://github.com/dpp/liftweb/issues/#issue/271 By the way, do you have any idea why my example application produces such weird results? I looked in the RequestVar code and didn't find anything there that would make it behave differently in the two scenarios. Adam Br's, Marius On Jan 5, 9:37 am, Adam Warski a...@warski.org wrote: Hello, Ah, I didn't spot this. I only have: lift:Msgs showAll=true/ which would suggest that it should show all errors. And anyway, why does it work then with normal form submit, and doesn't with ajax form submit? Adam On Jan 4, 2010, at 9:14 PM, Ross Mellgren wrote: S.error(NodeSeq) and S.error(List[FieldError]) differ in that the latter registers errors against particular fields, and the former is a page-wide error. The latter is more like S.error(String, NodeSeq). Do you have Msg snippets for each field, like this? ... field ... lift:msg id=my_field_id / (see net.liftweb.builtin.snippet.Msg for a better example) Hope that helps, -Ross On Jan 4, 2010, at 3:10 PM, Adam Warski wrote: Hello, investigating further making the tutorial form submittable with ajax, I found some weird behavior; I'm using 1.1-M8. It seems that when the form is submitted with ajax, and there are form validation errors, the error is not shown. However, the notices work fine. So: - S.notice(Added +todo.desc); shows the notice after the ajax form submit - S.error(xs); doesn't, only if the form is submitted in the regular way I didn't manage to find the problem yet, but if instead of calling S.error(xs); I do: xs.map {i = S.error(i.msg) }; the error is shown. The error(n: NodeSeq) and error(vi: List[FieldError]) don't seem to differ a lot, but there must be something special about the second. I tried to reproduce the problem using a simple application, but there I found another strange thing. The app is: object Test { def main(args: Array[String]) { val z = new ListBuffer[String] object x extends RequestVar(z) x += a object y extends RequestVar(new ListBuffer[String]) y += b println(x.is) println(y.is) } } and prints out: ListBuffer(a) ListBuffer() so for some reason, if the initial value of the RequestVar is passed without an intermediate val, the list content isn't modified. But it could be that I'm using the RequestVar outside of it's intended environment which may be the cause ;). -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com . For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en . -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Errors not shown after AJAX form submit
Ah so it's treated as a new request each time. Clear now, thanks :) Adam On Jan 5, 2010, at 3:31 PM, Naftoli Gugenheim wrote: I don't know the exact reason, but the parameter to the RequestVar constructor is a call by name, which means it's a function that can be re-evaluated. Normally this value is recalculated at the start of each request. In any case its seems that in your case they're being recalculated and restored to before you modified them. However in the first case that means referencing a variable that holds the change. - Adam Warskia...@warski.org wrote: Hello, I think the difference is in showAll scope. It was implemented for non Ajax context (just for msgs snippet) but it wasn't implemented for Ajax (as far as I can tell). Ajax notices (if there are any) are appended to user's JsCmd response. But this code has no idea about the showAll snippet attribute. Therefore ajax notices that are associates with an ID will not be shown in lift:Msgs showAll=true/ 's real estate. Please open a defect for this. I think I more or less understand :) Here's the defect: http://github.com/dpp/liftweb/issues/#issue/271 By the way, do you have any idea why my example application produces such weird results? I looked in the RequestVar code and didn't find anything there that would make it behave differently in the two scenarios. Adam Br's, Marius On Jan 5, 9:37 am, Adam Warski a...@warski.org wrote: Hello, Ah, I didn't spot this. I only have: lift:Msgs showAll=true/ which would suggest that it should show all errors. And anyway, why does it work then with normal form submit, and doesn't with ajax form submit? Adam On Jan 4, 2010, at 9:14 PM, Ross Mellgren wrote: S.error(NodeSeq) and S.error(List[FieldError]) differ in that the latter registers errors against particular fields, and the former is a page-wide error. The latter is more like S.error(String, NodeSeq). Do you have Msg snippets for each field, like this? ... field ... lift:msg id=my_field_id / (see net.liftweb.builtin.snippet.Msg for a better example) Hope that helps, -Ross On Jan 4, 2010, at 3:10 PM, Adam Warski wrote: Hello, investigating further making the tutorial form submittable with ajax, I found some weird behavior; I'm using 1.1-M8. It seems that when the form is submitted with ajax, and there are form validation errors, the error is not shown. However, the notices work fine. So: - S.notice(Added +todo.desc); shows the notice after the ajax form submit - S.error(xs); doesn't, only if the form is submitted in the regular way I didn't manage to find the problem yet, but if instead of calling S.error(xs); I do: xs.map {i = S.error(i.msg) }; the error is shown. The error(n: NodeSeq) and error(vi: List[FieldError]) don't seem to differ a lot, but there must be something special about the second. I tried to reproduce the problem using a simple application, but there I found another strange thing. The app is: object Test { def main(args: Array[String]) { val z = new ListBuffer[String] object x extends RequestVar(z) x += a object y extends RequestVar(new ListBuffer[String]) y += b println(x.is) println(y.is) } } and prints out: ListBuffer(a) ListBuffer() so for some reason, if the initial value of the RequestVar is passed without an intermediate val, the list content isn't modified. But it could be that I'm using the RequestVar outside of it's intended environment which may be the cause ;). -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com . For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en . -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en
[Lift] Errors not shown after AJAX form submit
Hello, investigating further making the tutorial form submittable with ajax, I found some weird behavior; I'm using 1.1-M8. It seems that when the form is submitted with ajax, and there are form validation errors, the error is not shown. However, the notices work fine. So: - S.notice(Added +todo.desc); shows the notice after the ajax form submit - S.error(xs); doesn't, only if the form is submitted in the regular way I didn't manage to find the problem yet, but if instead of calling S.error(xs); I do: xs.map {i = S.error(i.msg) }; the error is shown. The error(n: NodeSeq) and error(vi: List[FieldError]) don't seem to differ a lot, but there must be something special about the second. I tried to reproduce the problem using a simple application, but there I found another strange thing. The app is: object Test { def main(args: Array[String]) { val z = new ListBuffer[String] object x extends RequestVar(z) x += a object y extends RequestVar(new ListBuffer[String]) y += b println(x.is) println(y.is) } } and prints out: ListBuffer(a) ListBuffer() so for some reason, if the initial value of the RequestVar is passed without an intermediate val, the list content isn't modified. But it could be that I'm using the RequestVar outside of it's intended environment which may be the cause ;). -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Errors not shown after AJAX form submit
Hello, Ah, I didn't spot this. I only have: lift:Msgs showAll=true/ which would suggest that it should show all errors. And anyway, why does it work then with normal form submit, and doesn't with ajax form submit? Adam On Jan 4, 2010, at 9:14 PM, Ross Mellgren wrote: S.error(NodeSeq) and S.error(List[FieldError]) differ in that the latter registers errors against particular fields, and the former is a page-wide error. The latter is more like S.error(String, NodeSeq). Do you have Msg snippets for each field, like this? ... field ... lift:msg id=my_field_id / (see net.liftweb.builtin.snippet.Msg for a better example) Hope that helps, -Ross On Jan 4, 2010, at 3:10 PM, Adam Warski wrote: Hello, investigating further making the tutorial form submittable with ajax, I found some weird behavior; I'm using 1.1-M8. It seems that when the form is submitted with ajax, and there are form validation errors, the error is not shown. However, the notices work fine. So: - S.notice(Added +todo.desc); shows the notice after the ajax form submit - S.error(xs); doesn't, only if the form is submitted in the regular way I didn't manage to find the problem yet, but if instead of calling S.error(xs); I do: xs.map {i = S.error(i.msg) }; the error is shown. The error(n: NodeSeq) and error(vi: List[FieldError]) don't seem to differ a lot, but there must be something special about the second. I tried to reproduce the problem using a simple application, but there I found another strange thing. The app is: object Test { def main(args: Array[String]) { val z = new ListBuffer[String] object x extends RequestVar(z) x += a object y extends RequestVar(new ListBuffer[String]) y += b println(x.is) println(y.is) } } and prints out: ListBuffer(a) ListBuffer() so for some reason, if the initial value of the RequestVar is passed without an intermediate val, the list content isn't modified. But it could be that I'm using the RequestVar outside of it's intended environment which may be the cause ;). -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com . For more options, visit this group at http://groups.google.com/group/liftweb?hl=en . -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Snippet lifetime
Hello, Well for changing the tutorial form into an ajax form I guess the best solution is to store the model instance in a RequestVar and simply set it to a new instance after saving. So I don't have any immediate use-cases. But in other (Seam) projects I remember that I used the event scope (corresponding to TransientRequestVar) quite often, for example to have a single-request cache (things which may be invalidated even on the next ajax request). Also, I suppose that you need to hold a reference to all RequestVars as long as the user doesn't request another page, or as long as his session doesn't time out. You don't know if the page will make ajax callbacks or not, right? Sure we know since Lift's ajax functions that have bound Scala functions are inherently kept on the LiftSession. RequestVar's are preserved (and not only them) by a mechanism that we call snaphot- restorer which simply based on Scala's reference capturing. Right, but still, you don't know which variables are going to be used, so you need to keep them all. So if a page doesn't use ajax RequestVars are dereferenced right after the http request finishes? And even if you knew, you wouldn't know if the callbacks are going to use the vars. So potentially there may be a memory problem. I would expect request vars to be a bit lighter (a TransientRequestVar can be discarded right after the request processing finished). I really doubt the memory is an issue here. The amount of RequestVars used is typically quite low. Typically - yes, but I can bet there will be usages which will require a lot of them. I would not close the possibility for developers to decide if they want to store a variable in the real/transient request scope or in the page/request scope just because typically users want page/request scope variables. Maybe this should be the default, but certainly not the only option. Keep in mind that bound functions are subject to a garbage collection mechanism built in Lift. You may have noticed periodical __lift_GC__ Ajax request being sent from browser. This is a lease mechanism. So if bound functions are not revitalized they will expire and will be removed. I'll have to read up on how Lift handles this, I guess there was a chapter in the book :) -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Snippet lifetime
Hello, That's true in practice. The implementation of those methods however are equivalent to the S and SHtml versions except for the call to registerThisSnippet. But if Lift will sometimes remember even ordinary class instances as reusable snippets then why should the API for managing reused snippets be exclusive to StatefulSnippets? Why was this changed made, first of all? Why take away the flexibility to choose to use multiple instances of a class on the same page? And was a Breaking Change email sent out? If all snippets get placed in a RequestVar is there still a purpose in using RequestVars within a snippet? Another question I never got around to asking: Why does StatefulSnippet extend DispatchSnippet? I can only agree here. I'm quite new to Lift, but properties like if a snippet uses dispatch instead of reflection (= provides a dispatch methods) or if its instances can survive longer than a single http request (like StatefulSnippets or reflection snipptes right now) look like perfect candidates for traits. The developer would just then decide which traits to mix into his snippet, and then he would have exact control on how the snippets behave and what is their lifecycle. By the way, I find the names RequestVar and TransientRequestVar confusing also, but maybe that's because I come from a JEE/Seam background, where normally the Page/Request terminology is used. I don't know what names are used e.g. in RoR? -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Snippet lifetime
Hello, Yes, the article is out of date now... Lift now makes sure that multiple references to a single snippet in the same request context use the same instance of that snippet. I've updated the wiki page a bit: http://wiki.github.com/dpp/liftweb/about-snippets, if some lift gurus would want to review. So far it lists the following snippet kinds: * reflection * dispatch * singleton dispatch * stateful I'm not sure if there are any other, but if there are, maybe somebody could mention them there, so that people would be at least aware of their existence and look up in the source code later. -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Snippet lifetime
Hello, These are the names we use in Lift - appreciate what your saying, but its not confusing IMHO, just different to other things you are used to. Lift is Lift, not RoR, or Seam, or any other framework ;-) Sure, it's just a simple terminology switch, I don't really mind if they are named one way or the other. The only objection I would have is that I would make TransientRequestVar public, and, as Naftoli wrote, statefullness/dispatching a trait. -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Snippet lifetime
Hello, on the wiki page about reflection snippets (http://wiki.github.com/dpp/liftweb/about-snippets), it is written: Every time you call the reflection snippet in your markup code, a new instance is instantiated and the appropriate method invoked However this doesn't seem to be true (I'm using 1.1-M8). I have modified the example in the tutorial to use ajax to submit the form (as Marius and others advised me in another thread), and I discovered that after I add an item, then try to add another one, the first one is modified, which would mean that the same snippet instance is used (the snippet - TD - is a reflection snippet, as far as I understand the terminology). That would mean that reflection snippets have the same scope as RequestVars, that is that there's at most one instance per rendered page. Marius wrote that this changes recently, so maybe it's a side-effect? Also, do you think that RequestVar is a good name? For me it suggests a variable which has a lifecycle only for one http request. In the Seam framework, for example, there are two scopes: request and page (and many others), the first one being a true request scope, the second having essentially the same scope as RequestVar. So maybe it should be called PageVar? -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Snippet lifetime
Hello, Yes, the article is out of date now... Lift now makes sure that multiple references to a single snippet in the same request context use the same instance of that snippet. I see, so the rationale behind using dispatch snippets is out of date also. Except that you save one reflection call per page/request. So are there any reasons to use DispatchSnippets now? Reflection snippets do not have the same scope as request vars... rather, the snippet is held in a request var. Which essentialy makes them have the same scope as request vars :) By the way, is there a true request-scope variable? I saw that there's TransientRequestVar, but it's private in the liftweb package. Adam Cheers, Tim On 28 Dec 2009, at 14:33, Adam Warski wrote: Hello, on the wiki page about reflection snippets (http://wiki.github.com/dpp/liftweb/about-snippets), it is written: Every time you call the reflection snippet in your markup code, a new instance is instantiated and the appropriate method invoked However this doesn't seem to be true (I'm using 1.1-M8). I have modified the example in the tutorial to use ajax to submit the form (as Marius and others advised me in another thread), and I discovered that after I add an item, then try to add another one, the first one is modified, which would mean that the same snippet instance is used (the snippet - TD - is a reflection snippet, as far as I understand the terminology). That would mean that reflection snippets have the same scope as RequestVars, that is that there's at most one instance per rendered page. Marius wrote that this changes recently, so maybe it's a side-effect? Also, do you think that RequestVar is a good name? For me it suggests a variable which has a lifecycle only for one http request. In the Seam framework, for example, there are two scopes: request and page (and many others), the first one being a true request scope, the second having essentially the same scope as RequestVar. So maybe it should be called PageVar? -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Snippet lifetime
Hello, RequestVar-s lifetime is expanded beyond the actual request, which is not applicable for TransientRequestVar. For instance say you have a page and you set some state on a RequestVar ... then you render an Ajax link. After the page is rendered, when your ajax function is invoked, you RequestVar state set when rendering the page is still visible. But is there is problem you're chasing or is it just terminology? I understand the difference; and I think the terminology is a bit misleading. But right now I have two questions: 1) Can I have in lift a true request variable/snippet, that is such which has a lifetime of one request (without any ajax callbacks)? I can't use TransientRequestVar because it's private. It would be useful to complete my ajax-form example (after an item is saved, a new one should be used; I guess I could just store the model instance in a RequestVar and set it to a new object after saving, but maybe there's a nicer way). 2) Why would one want to use DispatchSnippets? The wiki says they are better because they are not instantiated whenever a tag is occurred. But right now, reflection snippets also aren't - they are instantiated at most once per request. Br's, Marius On Dec 28, 6:04 pm, Adam Warski a...@warski.org wrote: Hello, Yes, the article is out of date now... Lift now makes sure that multiple references to a single snippet in the same request context use the same instance of that snippet. I see, so the rationale behind using dispatch snippets is out of date also. Except that you save one reflection call per page/request. So are there any reasons to use DispatchSnippets now? Reflection snippets do not have the same scope as request vars... rather, the snippet is held in a request var. Which essentialy makes them have the same scope as request vars :) By the way, is there a true request-scope variable? I saw that there's TransientRequestVar, but it's private in the liftweb package. Adam Cheers, Tim On 28 Dec 2009, at 14:33, Adam Warski wrote: Hello, on the wiki page about reflection snippets (http://wiki.github.com/dpp/liftweb/about-snippets), it is written: Every time you call the reflection snippet in your markup code, a new instance is instantiated and the appropriate method invoked However this doesn't seem to be true (I'm using 1.1-M8). I have modified the example in the tutorial to use ajax to submit the form (as Marius and others advised me in another thread), and I discovered that after I add an item, then try to add another one, the first one is modified, which would mean that the same snippet instance is used (the snippet - TD - is a reflection snippet, as far as I understand the terminology). That would mean that reflection snippets have the same scope as RequestVars, that is that there's at most one instance per rendered page. Marius wrote that this changes recently, so maybe it's a side-effect? Also, do you think that RequestVar is a good name? For me it suggests a variable which has a lifecycle only for one http request. In the Seam framework, for example, there are two scopes: request and page (and many others), the first one being a true request scope, the second having essentially the same scope as RequestVar. So maybe it should be called PageVar? -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group athttp://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Snippet lifetime
Yes, the article is out of date now... Lift now makes sure that multiple references to a single snippet in the same request context use the same instance of that snippet. I see, so the rationale behind using dispatch snippets is out of date also. Except that you save one reflection call per page/request. So are there any reasons to use DispatchSnippets now? DispatchSnippets support dynamic dispatch: you can change how tags are dispatched based on some state. With (reflection-based) snippets, there's a direct binding between the tag and the class name + method. Well, unless you override LiftRules.snippetDispatch. Ah right. Thanks. I'll modify the wiki once I gather all the answers :) Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Snippet lifetime
Hello, 1) Can I have in lift a true request variable/snippet, that is such which has a lifetime of one request (without any ajax callbacks)? I can't use TransientRequestVar because it's private. It would be useful to complete my ajax-form example (after an item is saved, a new one should be used; I guess I could just store the model instance in a RequestVar and set it to a new object after saving, but maybe there's a nicer way). TransientRequestVar could technically be made public but I don't see compelling reasons to do that (yet). Do you need to do some logic right before sending down the response? What is your use-case? Well for changing the tutorial form into an ajax form I guess the best solution is to store the model instance in a RequestVar and simply set it to a new instance after saving. So I don't have any immediate use-cases. But in other (Seam) projects I remember that I used the event scope (corresponding to TransientRequestVar) quite often, for example to have a single-request cache (things which may be invalidated even on the next ajax request). Also, I suppose that you need to hold a reference to all RequestVars as long as the user doesn't request another page, or as long as his session doesn't time out. You don't know if the page will make ajax callbacks or not, right? And even if you knew, you wouldn't know if the callbacks are going to use the vars. So potentially there may be a memory problem. I would expect request vars to be a bit lighter (a TransientRequestVar can be discarded right after the request processing finished). -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Duplicate divs in tutorial
Heh, of course :) Can you (or somebody else) fix Listing 12 in the tutorial then? Adam On Dec 23, 2009, at 11:19 PM, Marius wrote: Why not something like: div id=all_todos lift:TD.list all_id=all_todos ... /lift:TD.list /div Br's, Marius On Dec 23, 11:46 pm, Adam Warski a...@warski.org wrote: Hello, just a note to the snippets written in the tutorial. The elements of the todo list, when changed (e.g. the done checkbox), submit and redraw the list. The code for that is (Listing 17): def list(html: NodeSeq) = { val id = S.attr(all_id).open_! def inner(): NodeSeq = { def reDraw() = SetHtml(id, inner()) bind(todo, html, exclude - ajaxCheckbox(QueryNotDone, v = {QueryNotDone(v); reDraw}), list - doList(reDraw) _) } inner() } And the corresponding template: lift:TD.list all_id=all_todos div id=all_todos !-- proper list -- /div /lift:TD.list As SetHtml sets the children of the element with the specified id, after one change of the checkbox and one ajax call, there will be a div id=all_todos inside the original div id=all_todos (as we set the children of the original element to be the nodes passed to the snippet). So you end up with: lift:TD.list all_id=all_todos div id=all_todos div id=all_todos !-- proper list -- /div /div /lift:TD.list Subsequent calls don't produce any more divs, as the children of the first div with id all_todos get replaced. However, I think it's not too clean to produce markup like that. The solution I think would be to (somehow) strip the outer div of the html NodeSeq and use that in the ajax reDraw method, instead of capturing the original html with a closure. But probably Lift gurus have a better solution :). -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
[Lift] Beginner Ajax question - redrawing a page fragment
Hello, I'm just starting with Lift, and there's one thing I can't figure out. I want to modify the ToDo example from the tutorial so that the Add button makes an ajax call, adds the element to a list and displays the modified result. The problem is that I don't know how to redraw the list after the button has been pressed. More generally: how to redraw a page fragment with ajax? I could do that with SetHtml if I had the NodeSeq corresponding to the list, but the button is in an unrelated page fragment so it doesn't have it. What's the Lift way to solve such problems? The page roughly is: lift:TD.add form=post !-- fields an submit button bound here -- /lift:TD.add !-- some other code -- !-- the list that I want to redraw -- lift:TD.list all_id=all_todos ... /lift:TD.list I was looking through the list archive but didn't find anything. Sorry if it's a repeated question :) -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Beginner Ajax question - redrawing a page fragment
Hello, With SetHtml you just provide the parent element ID and the NodeSeq you want to render as a child of that parent. You're saying you don;t have the NodeSeq Corresponding to the List but I assume you do have the list right? So assume this Ajax function: def myCallback(): JsCmd = { val myList = ... val html: NodeSeq = myList.flatMap(e = td{e toString}/td) SetHtml(all_todos, html) } But then I'm embedding view logic into the code - I wouldn't really want to do that. Especially once the list becomes anything more fancy then a simple table, I think putting the list-displaying into an html file better. I tried doing something else, expanding your idea. I've put the list-displaying html markup into a template (todo_list.html), so now I can reuse it to both display the list and pass it to the snippet which handles and binds the form: Now my form looks like this: lift:TD.add form=post addForm:form !-- fields and submit button bound here -- /addForm:form addForm:list lift:embed what=todo_list / /addForm:list /lift:TD.add !-- some other code -- !-- the list that I want to redraw -- lift:embed what=todo_list / In TD.add I have then: ... def drawList() = list(chooseTemplate(addForm, list, form)) def reDraw() = SetHtml(all_todos, drawList()) bind(todo, chooseTemplate(addForm, form, form), priority - todo.priority.toForm, desc - todo.desc.toForm, submit - submit(New, checkAndSave)) ) ... Is this the right way to go? And is it the lift way? Anyway I can't test it yet because I can't get my form to be submitted with ajax. Both surrounding the bind with SHtml.ajaxForm(...) and replacing submit with ajaxButton causes the form to stop working (the values in the model aren't updated). Adam Br's, Marius On Dec 23, 10:32 am, Adam Warski a...@warski.org wrote: Hello, I'm just starting with Lift, and there's one thing I can't figure out. I want to modify the ToDo example from the tutorial so that the Add button makes an ajax call, adds the element to a list and displays the modified result. The problem is that I don't know how to redraw the list after the button has been pressed. More generally: how to redraw a page fragment with ajax? I could do that with SetHtml if I had the NodeSeq corresponding to the list, but the button is in an unrelated page fragment so it doesn't have it. What's the Lift way to solve such problems? The page roughly is: lift:TD.add form=post !-- fields an submit button bound here -- /lift:TD.add !-- some other code -- !-- the list that I want to redraw -- lift:TD.list all_id=all_todos ... /lift:TD.list I was looking through the list archive but didn't find anything. Sorry if it's a repeated question :) -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en. -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Beginner Ajax question - redrawing a page fragment
Hello, object MyMarkupVar extends RequestVar[NodeSeq](NodeSeq.empty) ah, that's much better then my solution. Thanks! :) Maybe you could also write, how to submit a whole form using AJAX? :) So far my attempts are futile. I get an ajax request, but the value of the field isn't bound to the model. Code of my snippet, without ajax (works): bind(todo, chooseTemplate(addForm, form, form), desc - todo.desc.toForm, submit - submit(New, checkAndSave)) ) With ajax (doesn't work): ajaxForm( bind(todo, chooseTemplate(addForm, form, form), desc - todo.desc.toForm, submit - submit(New, checkAndSave)) ) Or: bind(todo, chooseTemplate(addForm, form, form), desc - todo.desc.toForm, submit - ajaxButton(New, () = {checkAndSave; reDraw()})) ) -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
Re: [Lift] Re: Beginner Ajax question - redrawing a page fragment
Hello, A couple of observations... First, having some XHTML in your Scala code is not a bad thing. When the XHTML declares the meaning (not the layout) of the information, it's my opinion that it's okay. This means that: ul{list.map(i = li{i}/li}ul Simply defines an unordered list. It does not declare how to lay out that list. The layout should be controlled by CSS. True, xhtml can also be considered as logic. You got me convinced ;). TemplateFinder.findAnyTemplate(List(snippets-hidden, userList)) openOr NodeSeq.Empty) Worked great; lots of Lift API to explore still :). If you don't mind, I'll put the results of this thread in a tutorial-ajax-followup wiki page? I think quite a lot of people may want to do something similar. -- Adam -- You received this message because you are subscribed to the Google Groups Lift group. To post to this group, send email to lift...@googlegroups.com. To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.