2012-04-06 12 views
8

Me gustaría utilizar un autocompletar con ajax. Así que mi objetivo es tener:Levante - Autocompletar con Ajax Envío

  • Cuando el usuario escribe algo en el campo de texto, algunas sugerencias proporcionadas por el servidor aparece (Tengo que encontrar sugerencias en una base de datos)

  • cuando el usuario presiona "enter", hace clic en otro lugar que no sea en el cuadro de autocompletar, o cuando selecciona una sugerencia, la cadena en el campo de texto se envía al servidor.

primera vez que trató de utilizar el widget de autocompletar proporcionada por ascensor, pero me enfrentaba a tres problemas:

  • que está destinado a ser un selecto extendida, es decir que puede originalmente sólo presentar valores sugeridos .
  • no está destinado a ser utilizado con ajax.
  • se pone defectuoso cuando se combina con WiringUI.

Entonces, mi pregunta es: ¿Cómo puedo combinar jquery autocomplete e interactuar con el servidor en ascensor? Creo que debería usar algunas devoluciones de llamada pero no las domino.

Gracias de antemano.

ACTUALIZACIÓN He aquí una primera implementación Lo intenté, pero la devolución de llamada no funciona:

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

Así que mi idea era:

  • para obtener el resultado seleccionado a través de un campo SHtml.ajaxText cuales se wraped en un campo de autocompletar
  • para actualizar las sugerencias de autocompletado utilizando una función de JavaScript

Respuesta

8

Esto es lo que debe hacer.

1) Asegúrese de que está utilizando Lift 2.5-SNAPSHOT (esto es factible en las versiones anteriores, pero es más difícil)

2) En el fragmento que se utiliza para representar la página, utilice SHtml.ajaxCall (en en particular, probablemente desee esta versión: https://github.com/lift/framework/blob/master/web/webkit/src/main/scala/net/liftweb/http/SHtml.scala#L170) que le permitirá registrar una función del lado del servidor que acepte su término de búsqueda y devolver una respuesta JSON que contenga las terminaciones. También registrará alguna acción que ocurra en la respuesta JSON con el JsContext.

3) El ajaxCall anterior devolverá un objeto JsExp lo que resultará en la solicitud ajax cuando se invoca. Incrustarlo dentro de una función de javascript en la página usando su fragmento.

4) cablearlas con un poco de JS lado del cliente.

actualización - algo de código para ayudarte. Definitivamente se puede hacer de forma más sucinta con Lift 2.5, pero debido a algunas inconsistencias en 2.4 terminé rodando mi propia función llamada ajaxCall. S.fmapFunc registra la función en el lado del servidor y el cuerpo de la función realiza una llamada Lift ajax desde el cliente, luego invoca la función res (que proviene de la autocompletación de jQuery) en la respuesta JSON.

Mi plugin de jQuery para "activar" la entrada de texto


(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); 

Mi código Scala que da lugar a la función javascript búsqueda:


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');" + 
     """ 
     } 
     """) 

Actualización 2 - Para añadir la función de arriba a su página, use una transformación CssSelector similar a la siguiente. El> * significa agregar a todo lo que ya existe dentro del elemento de script coincidente. Tengo otras funciones que he definido en esa página, y esto les agrega la función de búsqueda.


"script >*" #> autoCompleteJs 

Puede ver la fuente para verificar que existe en la página y se puede llamar al igual que cualquier otra función JS.

+0

Hola, lamentablemente no puedo usar Lift 2.5. Estoy en el ascensor 2.4 M4. Sin embargo, por lo que ya he usado, parece que ya hay callbacks implementados en 2.4. Gracias por tu respuesta. –

+0

Actualicé mi pregunta con el momento en que estoy bloqueado, cualquier sugerencia es bienvenida. –

+0

No estoy seguro de a qué se refiere cuando dice que la devolución de llamada no funciona. ¿Se ejecuta update_source? Si es así, su problema es probable con su devolución. Está realizando una llamada asincrónica, por lo que solo devolver el JSON no es suficiente, el navegador no sabrá qué hacer con él. Tendrá que devolver un JsCmd que realice una acción, y el resultado de esa acción debería ser la población de la autocompletar de JQuery UI. –

2

Con la ayuda de Dave Whittaker, esta es la solución con la que vine.

que tenía que cambiar algunos comportamientos para obtener:

  • el texto deseado (de autocompletar o no) en un elemento ajaxText
  • la posibilidad de tener múltiples formas de autocompletar en la misma página
  • presentar respuesta en ajaxTexto antes de difuminar cuando se selecciona algo en las sugerencias de autocompletar.

Scala parte

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) 
} 

de secuencias de comandos para insertar en la página de encabezamiento:

(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); 

Nota: acepté respuesta de Dave, la mía es sólo para dar una respuesta completa para mi propósito

Cuestiones relacionadas