2014-03-02 66 views
0

截至目前(道場1.9.2),我一直沒能找到一個Dojo自動完成構件,將滿足所有的以下(典型值)的要求:全功能自動完成構件的道場

  • 只有執行查詢服務器時已經輸入的字符的預定數量(不這樣做,大的數據集不應該被質疑)
  • 是否要求全REST服務在服務器上,只有一個網址,其可以用搜索詞進行參數化,並簡單地返回JSON對象含有一個ID和一個標籤,以顯示TS(所以數據查詢到數據庫可以被限制只到所需的數據字段,不加載完整的數據實體和使用之後只有一個字段)
  • 具有可配置的時間延遲鍵版本和服務器查詢的開始之間(不包括查詢這個人數過多對服務器解僱)
  • 能夠識別的時候有無需新的服務器查詢(因爲先前執行的查詢比當前查詢更通用)。
  • 下拉-stlye(具有指示這是一個選擇場GUI元素)

我已經創建了一個解決方案草案(見下文),請告知,如果你有一個更簡單,更好的解決了以上Dojo要求> 1.9。

回答

0

自動完成插件作爲道場AMD模塊(根據AMD規則放入/gefc/dijit/AutoComplete.js):

// 
// AutoComplete style widget which works together with an ItemFileReadStore 
// 
// It will re-query the server whenever necessary. 
// 
define([ 
    "dojo/_base/declare", 
    "dijit/form/FilteringSelect" 
], 
function(declare, _FilteringSelect) { 
    return declare(
    [_FilteringSelect], { 

     // minimum number of input characters to trigger search 
     minKeyCount: 2, 

     // the term for which we have queried the server for the last time 
     lastServerQueryTerm: null, 

     // The query URL which will be set on the store when a server query 
     // is needed 
     queryURL: null, 
     //------------------------------------------------------------------------ 
     postCreate: function() { 
     this.inherited(arguments); 
     // Setting defaults 
     if (this.searchDelay == null) 
      this.searchDelay = 500; 
     if (this.searchAttr == null) 
      this.searchAttr = "label"; 
     if (this.autoComplete == null) 
      this.autoComplete = true; 
     if (this.minKeyCount == null) 
      this.minKeyCount = 2; 
     },  
     escapeRegExp: function (str) { 
     return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 
     }, 
     replaceAll: function (find, replace, str) { 
     return str.replace(new RegExp(this.escapeRegExp(find), 'g'), replace); 
     }, 
     startsWith: function (longStr, shortStr) { 
     return (longStr.match("^" + shortStr) == shortStr) 
     }, 
     // override search method, count the input length 
     _startSearch: function (/*String*/ key) { 

     // If there is not enough text entered, we won't start querying 
     if (!key || key.length < this.minKeyCount) { 
      this.closeDropDown(); 
      return; 
     } 

     // Deciding if the server needs to be queried 
     var serverQueryNeeded = false; 

     if (this.lastServerQueryTerm == null) 
      serverQueryNeeded = true; 
     else if (!this.startsWith(key, this.lastServerQueryTerm)) { 
      // the key does not start with the server queryterm 
      serverQueryNeeded = true; 
     } 

     if (serverQueryNeeded) { 
      // Creating a query url templated with the autocomplete term 
      var url = this.replaceAll('${autoCompleteTerm}', key, this.queryURL); 
      this.store.url = url 
      // We need to close the store in order to allow the FilteringSelect 
      // to re-open it with the new query term 
      this.store.close(); 
      this.lastServerQueryTerm = key; 
     } 

     // Calling the super start search 
     this.inherited(arguments); 
     } 
    } 
); 
}); 

  • 我包括一些串函數使其獨立,這些應該去你的JS庫中的適當位置。

中的JavaScript嵌入到其使用德自動完成插件的頁面:

require([ 
    "dojo/ready", 
    "dojo/data/ItemFileReadStore", 
    "gefc/dijit/AutoComplete", 
    "dojo/parser" 
    ], 
    function(ready, ItemFileReadStore, AutoComplete) { 

    ready(function() { 

     // The initially displayed data (current value, possibly null) 
     // This makes it possible that the widget does not fire a query against 
     // the server immediately after initialization for getting a label for 
     // its current value 
     var dt = null; 
     <g:if test="${tenantInstance.technicalContact != null}"> 
     dt = {identifier:"id", items:[ 
      {id: "${tenantInstance.technicalContact.id}", 
      label:"${tenantInstance.technicalContact.name}" 
      } 
     ]}; 
     </g:if> 

     // If there is no current value, this will have no data 
     var partnerStore = new ItemFileReadStore(
     { data: dt, 
      urlPreventCache: true, 
      clearOnClose: true 
     } 
    ); 

     var partnerSelect = new AutoComplete({ 
     id: "technicalContactAC", 
     name: "technicalContact.id", 
     value: "${tenantInstance?.technicalContact?.id}", 
     displayValue: "${tenantInstance?.technicalContact?.name}", 
     queryURL: '<g:createLink controller="partner" 
      action="listForAutoComplete" 
      absolute="true"/>?term=\$\{autoCompleteTerm\}', 
     store: partnerStore, 
     searchAttr: "label", 
     autoComplete: true 
     }, 
     "technicalContactAC" 
    ); 

    }) 
    }) 

  • 這不是獨立JavaScript,但產生與在服務器端的Grails,因此您在代碼中看到<g:if...和其他服務器端標記)。用你自己的標記替換這些部分。
  • <g:createLink將導致服務器端頁面生成後是這樣的:/Limes/partner/listForAutoComplete?term=${autoCompleteTerm}
0

由於道場1.9的,我會通過,建議您從道場/存儲包商店更換你的ItemFileReadStore開始。

然後,我認爲dijit/form/FilteringSelect已經有了你需要的功能。

考慮您的要求,以避免在初始頁面啓動服務器往返,我會設置2個不同的商店:

然後,爲了避免在每次擊鍵時查詢服務器,請將FilteringSelect的intermediateChanges屬性設置爲false,並在onChange擴展點上實現您的邏輯。

對於延遲後觸發服務器調用的要求,也可以在onChange中實現。在下面的例子中,我做了一個簡單的setTimeout,但你應該考慮寫一個更好的去抖動方法。看到這個blog postutility functions of dgrid

我會做到這一點在你的GSP頁面:

require(["dojo/store/Memory", "dojo/store/JsonRest", "dijit/form/FilteringSelect", "dojo/_base/lang"], 
function(Memory, JsonRest, FilteringSelect, lang) { 
    var initialPartnerStore = undefined; 

    <g:if test="${tenantInstance.technicalContact != null}"> 
     dt = {identifier:"id", items:[ 
      {id: "${tenantInstance.technicalContact.id}", 
      label:"${tenantInstance.technicalContact.name}" 
      } 
     ]}; 
     initialPartnerStore = new Memory({ 
      data : dt 
     }); 
    </g:if> 

    var partnerStore = new JsonRest({ 
     target : '<g:createLink controller="partner" action="listForAutoComplete" absolute="true"/>', 
    }); 

    var queryDelay = 500; 

    var select = new FilteringSelect({ 
     id: "technicalContactAC", 
     name: "technicalContact.id", 
     value: "${tenantInstance?.technicalContact?.id}", 
     displayValue: "${tenantInstance?.technicalContact?.name}", 
     store: initialPartnerStore ? initialPartnerStore : partnerStore, 
     query : { term : ${autoCompleteTerm} }, 
     searchAttr: "label", 
     autoComplete: true, 
     intermediateChanges : false, 
     onChange : function(newValue) { 
      // Change to the JsonRest store to query the server 
      if (this.store !== partnerStore) { 
       this.set("store", partnerStore); 
      } 

      // Only query after your desired delay 
      setTimeout(lang.hitch(this, function(){ 
       this.set('query', { term : newValue } 
      }), queryDelay); 

     } 
    }).startup(); 

});  

此代碼是未經測試,但你的想法...