Yes please a small app would be best. Please use 2.0-SNAPSHOT.

Also please see this thread: 
http://groups.google.com/group/liftweb/browse_thread/thread/75750c42ec3a2d7d?hl=en#

Br's,
Marius

On Jan 13, 10:07 am, Adam Warski <[email protected]> wrote:
> 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_form"id, () => { 
> 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 <[email protected]> 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
> >>> 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 <[email protected]> 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 <[email protected]> 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",
>
> ...
>
> read more »
-- 
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


Reply via email to