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.


Reply via email to