Arosh
Arosh

Reputation: 131

Lift Ajax multi select box

I am new to scala and lift and I want to make a form with some ajax. Therefore main form is from normal stateful snippet and middle content is enclosed with some ajax form(there content in another snippet but not Stateful because I cant use ValueCell in Stateful).

In there I want to add dynamically any no. of multi-select boxes as user want by pressing "ADD" button.

I did it for normal drop-down select by selecting SHtml.ajaxSelect() and save in ValueCell and also save in a session context.

Here I can use ValueCell to store data because ajaxSelect support for ajax. But in multi-select there are not "ajaxMultiSelect"?? So I need to retrieve the data from those dynamically added multi-select boxes to my form variables when pressing submit button in the overall form.

http://seventhings.liftweb.net/wiring - this example is my guide to do my task. Here they use dynamically add text fields. But I want to add multiselect and save data when hitting submit button.

Please help me someone. If u want further clarification I can give.

Thank you ALL...

Upvotes: 10

Views: 1115

Answers (2)

Austen Holmes
Austen Holmes

Reputation: 1939

I know this is a bit of an older question, but here's my shot (since there still doesn't appear to be an ajax multiSelect in the latest snapshots), and I could see it coming in handy

You can base it off of the regular ajaxSelect. The main changes are:

  1. You have to extract all the values and submit them (the form submission is just regular urlEncoded postParams), but this is the most unclear if you are just glancing at how to do this.
  2. You have to change the default value to a Seq[String] (this also requres changing the test to see if selected should be set)
  3. You have to decide whether you want the callback on change or on blur. In my example, I'll make it onblur, but you could make it configurable.

      private def ajaxMultiSelect_*(opts: Seq[(String, String)], deflt: Seq[String], jsFunc: Box[Call], func: AFuncHolder, attrs: ElemAttr*): Elem = {
        val optionSelect =
        """function(funcName, element) {
          |  var postData = ""
          |  var i = 0;
          |  var k = 0;
          |  for (k = 0; k < element.length; k++) {
          |   if (element[k].selected) {
          |     if (i == 0)
          |       postData = funcName + '=' + encodeURIComponent(element[k].value);
          |     else {
          |       postData = postData + '&' + funcName + '=' + encodeURIComponent(element[k].value);
          |     }
          |     i++;
          |   }
          |  }
          |  return postData;
          |}""".stripMargin
    
        val raw = (funcName: String, value: String) => JsRaw(optionSelect + "('" + funcName + "'," + value + ")")
        val key = formFuncName
    
        val vals = opts.map(_._1)
        val testFunc = LFuncHolder(in => in.filter(v => vals.contains(v)) match {case Nil => false case xs => func(xs)}, func.owner)
        fmapFunc((testFunc)) {
          funcName =>
              (attrs.foldLeft(<select multiple="multiple">{opts.flatMap {case (value, text) => (<option value={value}>{text}</option>) % selected(default.contains(value)))}}</select>)(_ % _)) %
                  ("onblur" -> (jsFunc match {
                      case Full(f) => JsCrVar(key, JsRaw("this")) & deferCall(raw(funcName, key), f)
                      case _ => makeAjaxCall(raw(funcName, "this"))
                  }))
        }
     }
    

This should be working, but I didn't test it. If I have time, I'll test it and see if I can get it (and its overloads) added to the master branch.

Good Luck!

-Austen

Upvotes: 0

Donald.McLean
Donald.McLean

Reputation: 899

If all you want is multi-selects whose values can be sent to the server when user pushes a "save" button, then a bunch of SHtml.multiselect objects on an AJAX form should be sufficient.

On the other hand, if you need an AJAX call every time the user changes the value of a multi-select then you probably have to use the same SHtml.multiselect but add an onchange event handler that calls a JavaScript function containing an ajaxCall.

Here's a bit that creates a JavaScript function doCallback() and adds it to the page at #placeholder. This calls commandCallback(commandString) on the server.

val log = SHtml.ajaxCall(JsRaw("commandString"), commandCallback _)._2.cmd
val f = JsCmds.Function("doCallback", List[String](), log)
("#placeholder" #> JsCmds.Script(f)).apply(ns)

Upvotes: 2

Related Questions