2012-04-06 16 views
8

Vorrei utilizzare un completamento automatico con ajax. Quindi il mio obiettivo è quello di avere:Lift - Completamento automatico con invio Ajax

  • Quando l'utente digita qualcosa nel campo di testo, appaiono alcuni suggerimenti forniti dal server (devo trovare suggerimenti in un database)

  • quando l'utente preme "inserisci", fa clic da qualche altra parte rispetto alla casella di completamento automatico o quando lui/lei seleziona un suggerimento, la stringa nel campo di testo viene inviata al server.

ho provato ad utilizzare il widget di completamento automatico fornito da ascensore ma ho dovuto affrontare tre problemi:

  • è destinata ad essere un selezionare esteso, vale a dire che si può inizialmente presentare soltanto i valori suggeriti .
  • non è pensato per essere utilizzato con Ajax.
  • diventa difettoso se combinato con WiringUI.

Quindi, la mia domanda è: Come posso combinare jquery autocomplete e interagire con il server in ascensore. Penso che dovrei usare alcune callback ma non le controllo.

Grazie in anticipo.

UPDATE Ecco una prima implementazione ho provato ma il callback non funziona:

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

Quindi la mia idea era:

  • per ottenere il risultato selezionato tramite un campo SHtml.ajaxText che sarebbe stato inserito in un campo di completamento automatico
  • per aggiornare i suggerimenti di completamento automatico utilizzando una funzione javascript

risposta

8

Ecco cosa è necessario fare.

1) Assicurarsi che si sta utilizzando Ascensore 2.5-SNAPSHOT (questo è fattibile nelle versioni precedenti, ma è più difficile)

2) Nel frammento che si utilizza per il rendering della pagina, utilizzare SHtml.ajaxCall (in In particolare, probabilmente si desidera questa versione: https://github.com/lift/framework/blob/master/web/webkit/src/main/scala/net/liftweb/http/SHtml.scala#L170 che consente di registrare una funzione lato server che accetta il termine di ricerca e restituisce una risposta JSON contenente i completamenti. Registrerai anche alcune azioni da eseguire sulla risposta JSON con JsContext.

3) L'ajaxCall sopra restituirà un oggetto JsExp che genererà la richiesta ajax quando viene richiamata. Incorporalo in una funzione javascript sulla pagina utilizzando il frammento di codice.

4) Collegarli con un lato client JS.

Aggiornamento - Un codice per aiutarti. Può sicuramente essere fatto in modo più sintetico con Lift 2.5, ma a causa di alcune incoerenze nella 2.4 ho finito con il rollare la mia funzione simile a ajaxCall. S.fmapFunc registra la funzione sul lato server e il corpo della funzione effettua una chiamata Lift ajax dal client, quindi richiama la funzione res (che deriva dal completamento automatico jQuery) nella risposta JSON.

mio plugin per jQuery per "attivare" il metodo di scrittura


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

mio codice Scala che si traduce nella funzione di ricerca javascript:


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

Update 2 - Per aggiungere la funzione di cui sopra a la tua pagina, usa una trasformazione CssSelector simile a quella qui sotto. Il simbolo * indica appendice a tutto ciò che esiste già all'interno dell'elemento di script corrispondente. Ho altre funzioni che ho definito su quella pagina e questo aggiunge loro la funzione di ricerca.


"script >*" #> autoCompleteJs 

È possibile visualizzare l'origine per verificare che esista sulla pagina e possa essere richiamata come qualsiasi altra funzione JS.

+0

Ciao, sfortunatamente non riesco a utilizzare l'ascensore 2.5. Sono sull'ascensore 2.4 M4. Tuttavia, da quello che ho già usato, sembra che ci siano già dei callback implementati in 2.4. Grazie per la tua risposta. –

+0

Ho aggiornato la mia domanda con il momento in cui sono bloccato, qualsiasi suggerimento è benvenuto. –

+0

Non sono sicuro di cosa intendi quando dici che il callback non funziona. Update_source è eseguito? Se è così, il tuo problema è probabile con il tuo ritorno. Stai facendo una chiamata asincrona, quindi non è sufficiente restituire il JSON, il browser non saprà cosa fare con esso. Dovrai restituire un JsCmd che esegue un'azione e il risultato di tale azione dovrebbe essere il popolamento del completamento automatico dell'interfaccia utente JQuery. –

2

Con l'aiuto di Dave Whittaker, ecco la soluzione con cui sono arrivato.

ho dovuto cambiare alcuni comportamenti per ottenere:

  • il testo desiderato (da completamento automatico o meno) in un elemento ajaxText
  • la possibilità di avere molteplici forme di completamento automatico sulla stessa pagina
  • presentare risposta su ajaxText prima della sfocatura quando qualcosa è selezionato nei suggerimenti di completamento automatico.

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

script da inserire nella pagina di intestazione:

(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: ho accettato la risposta di Dave, il mio è solo quello di fornire una risposta completa per il mio scopo

Problemi correlati