Jquery ui Lift-使用Ajax提交自动完成

Jquery ui Lift-使用Ajax提交自动完成,jquery-ui,scala,callback,lift,Jquery Ui,Scala,Callback,Lift,我想在ajax中使用自动完成。因此,我的目标是: 当用户在文本字段中键入内容时,服务器提供的一些建议就会出现,我必须在数据库中查找建议 当用户按enter键、单击“自动完成”框以外的其他位置时,或者当用户选择建议时,文本字段中的字符串将发送到服务器 我第一次尝试使用lift提供的autocomplete小部件,但遇到了三个问题: 它是一个扩展选择,也就是说,您最初只能提交建议值。 它并不打算与ajax一起使用。 当与WiringUI结合时,它会出现bug。 所以,我的问题是:如何在lift中与服

我想在ajax中使用自动完成。因此,我的目标是:

当用户在文本字段中键入内容时,服务器提供的一些建议就会出现,我必须在数据库中查找建议

当用户按enter键、单击“自动完成”框以外的其他位置时,或者当用户选择建议时,文本字段中的字符串将发送到服务器

我第一次尝试使用lift提供的autocomplete小部件,但遇到了三个问题:

它是一个扩展选择,也就是说,您最初只能提交建议值。 它并不打算与ajax一起使用。 当与WiringUI结合时,它会出现bug。 所以,我的问题是:如何在lift中与服务器进行组合和交互。我想我应该使用一些回调,但我没有掌握它们

提前谢谢

更新此处是我尝试的第一个实现,但回调不起作用:

private def update_source(current: String, limit: Int) = {   
  val results = if (current.length == 0) Nil else /* generate list of results */
  new JsCmd{def toJsCmd = if(results.nonEmpty) results.mkString("[\"", "\", \"", "\"]") else "[]" }
}   

def render = {
  val id = "my-autocomplete"
  val cb = SHtml.ajaxCall(JsRaw("request"), update_source(_, 4))
  val script = Script(new JsCmd{
    def toJsCmd = "$(function() {"+
      "$(\"#"+id+"\").autocomplete({ "+
      "autocomplete: on, "+
      "source: function(request, response) {"+
        "response("+cb._2.toJsCmd + ");"  +
      "}"+
      "})});"
  })

  <head><script charset="utf-8"> {script} </script></head> ++
  <span id={id}> {SHtml.ajaxText(init, s=>{ /*set cell to value s*/; Noop}) }   </span>
}
所以我的想法是:

通过SHtml.ajaxText字段获取所选结果,该字段将被包装到自动完成字段中 使用javascript函数更新自动完成建议
这是你需要做的

1确保您使用的是Lift 2.5-SNAPSHOT,这在早期版本中是可行的,但更困难

2在用于呈现页面的代码段中,请特别使用SHtml.ajaxCall,您可能需要此版本:它将允许您注册一个服务器端函数,该函数接受您的搜索词并返回包含完成项的JSON响应。您还将在JsContext中注册JSON响应上发生的一些操作

3上面的ajaxCall将返回一个JsExp对象,调用该对象时将产生ajax请求。使用您的代码片段将其嵌入页面上的javascript函数中

4用一些客户端JS将它们连接起来

更新-一些代码来帮助你。使用Lift 2.5肯定可以更简洁地完成,但由于2.4中的一些不一致,我最终使用了自己的ajaxCall类函数。S.fmapFunc在服务器端注册函数,函数体从客户机发出Lift ajax调用,然后在JSON响应上调用来自jQuery autocomplete的res函数

我的jQuery插件用于激活文本输入


(function($) {
    $.fn.initAssignment = function() {
     return this.autocomplete({
         autoFocus: true,
         source: function(req, res) {
              search(req.term, res);
         },
         select: function(event, ui) {
             assign(ui.item.value, function(data){
                eval(data);
             });
             event.preventDefault();
             $(this).val("");
         },
         focus: function(event, ui) {
             event.preventDefault();
         }
     });
    }
})(jQuery);
生成javascript搜索函数的我的Scala代码:


def autoCompleteJs = JsRaw("""
        function search(term, res) {
        """ +
             (S.fmapFunc(S.contextFuncBuilder(SFuncHolder({ terms: String =>
                val _candidates = 
                  if(terms != null && terms.trim() != "")
                    assigneeCandidates(terms)
                  else
                    Nil
                JsonResponse(JArray(_candidates map { c => c.toJson }))
             })))
             ({ name => 
               "liftAjax.lift_ajaxHandler('" + name 
             })) + 
             "=' + encodeURIComponent(term), " +
             "function(data){ res(data); }" +
             ", null, 'json');" +
        """
        }
        """)
更新2-要将上面的函数添加到页面中,请使用与下面类似的CssSelector转换。>*表示附加到匹配脚本元素中已经存在的任何内容。我在该页面上定义了其他函数,这将为它们添加搜索函数


"script >*" #> autoCompleteJs

您可以查看源代码以验证它是否存在于页面上,并且可以像调用任何其他JS函数一样调用它。

在Dave Whittaker的帮助下,我提供了一个解决方案

我必须改变一些行为才能得到:

ajaxText元素中是否包含自动完成所需的文本 在同一页面上有多个自动完成表单的可能性 在自动完成建议中选择内容时,在模糊之前提交ajaxText上的答案。 鳞片部分

要插入到页眉中的脚本:


注意:我接受了Dave的回答,我的回答只是为了提供一个完整的答案

嗨,很遗憾我不能使用Lift 2.5。我在电梯2.4 M4上。然而,从我已经使用过的内容来看,似乎已经在2.4中实现了回调。谢谢你的回答。当我现在被阻止的时候,我更新了我的问题,欢迎任何建议。我不知道你说回调不起作用是什么意思。是否执行更新源?如果是这样,你的问题很可能是你的回报。您正在进行异步调用,因此仅返回JSON是不够的,浏览器将不知道如何处理它。您需要返回一个执行操作的JsCmd,该操作的结果应该是jQueryUI自动完成的填充。我理解您的意思,通过我发布的代码,单元格更新可以正常工作。你认为修改函数update_源代码就足够了吗?如果足够,你能给我一些代码吗?Javascript不是我的强项。你的编辑给人留下了深刻的印象,将Javascript和lift链接起来是不可思议的。但是我有点迷路了,我不知道在我的代码中在哪里使用函数autoCompleteJs。我必须保留函数脚本并将autoCompleteJs用作ajaxCallautoCompleteJs,还是必须将回调放在其他位置?
private def getSugggestions(current: String, limit: Int):List[String] = {
  /* returns list of suggestions */
}

private def autoCompleteJs = AnonFunc("term, res",JsRaw(
  (S.fmapFunc(S.contextFuncBuilder(SFuncHolder({ terms: String =>
    val _candidates =
      if(terms != null && terms.trim() != "")
        getSugggestions(terms, 5)
      else
        Nil
    JsonResponse(JArray(_candidates map { c => JString(c)/*.toJson*/ }))
  })))
  ({ name =>
    "liftAjax.lift_ajaxHandler('" + name
  })) +
  "=' + encodeURIComponent(term), " +
  "function(data){ res(data); }" +
  ", null, 'json');"))


def xml = {
  val id = "myId" //possibility to have multiple autocomplete fields on same page
  Script(OnLoad(JsRaw("jQuery('#"+id+"').createAutocompleteField("+autoCompleteJs.toJsCmd+")")))     ++
  SHtml.ajaxText(cell.get, s=>{ cell.set(s); SearchMenu.recomputeResults; Noop}, "id" -> id)
}
(function($) {
    $.fn.createAutocompleteField = function(search) {
        return this.autocomplete({
            autoFocus: true,
            source: function(req, res) {
                search(req.term, res);
            },
            select: function(event, ui) {
                $(this).val(ui.item.value);
                $(this).blur();
            },
            focus: function(event, ui) {
                event.preventDefault();
            }
        });
    }
})(jQuery);