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 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 >>> 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.