2011-08-27 72 views
1

請耐心等待,因爲我試圖解釋這一點,因爲它有點複雜,我對JQuery完全陌生,並且試圖讓我的頭腦清楚。爲jquery模板附加包含html的腳本

我和我的團隊正在研究WebParts的SharePoint項目。 WebPart包含一個用戶控件(SearchControl),它有一個鏈接來打開一個包含另一個用戶控件(SelectorControl)的對話框(使用jquery ui)。

SelectorControl包含:

  • 被使用JQuery模板填充下拉列表(objTemplates)
  • 正在使用另一個JQuery的模板填充的表格;和
  • 只讀文本輸入從表格中顯示當前選擇的項目

SelectorControl代碼:

 <div class="objSelector"> 
     <script id="objSelectorTemplate" type="text/x-jquery-tmpl"> 
     <div class="table"> 
      <div class="row"> 
       <div class="labelInputGroup"> 
        <label for="objTemplates">Obj Template</label> 
        <select id="objTemplates"> 
         {{each ObjectTemplates}} 
          <option value="${ObjectTemplateId}">${Name}</option> 
         {{/each}} 
        </select> 
       </div> 
      </div> 
      <div><br></div> 
      <div class="row"> 
       <div> 
        <table class="tableGrid"> 
         <thead> 
          <tr> 
           <th>Object Name</th> 
          </tr> 
         </thead> 
         <tbody id="listPlaceholder"> 
         </tbody> 
        </table> 
        <div id="pagerPlaceholder"></div> 
       </div>   
      </div>  
      <div id="templatePlaceholder"> 
      </div> 
      <div><br></div> 
      <div class="row"> 
       <input type="hidden" id="localSelectedObjectId" class="hidden" /> 
       <label for="localSelectedObject">Selected Object</label> 
       <input type="text" class="dealName" id="localSelectedObject" readonly="readonly" placeholder="No object selected"/> 
      </div> 
     </div> 
     </script>  
     <script id="listTemplate" type="text/x-jquery-tmpl"> 
      <tr> 
       <td><a class="objectItem" id="${Id}" href="#">${Name}</a></td> 
      </tr> 
     </script>  
     <div id="pagerControl"> 
      <uc1:PagerControl ID="PagerControl1" runat="server" /> 
     </div> 
    </div> 

的下拉列表只是填充對話之前,使用從檢索到的數據被創建一個WCF服務,然後綁定到第一個模板。

'change'事件綁定到下拉列表,使用live通過調用WCF服務並通過下拉列表中的當前選定項目來填充表(第二個模板)。

當觸發下拉列表中的變化時,裝入對象被稱爲:

  function LoadObjects(event) { 

      var dialogDom = event.data.DialogDom; 
      var searchObj = GetSearchFilters(); // removed irrelevant code here 

      var listTemplate = searchDom.find('#listTemplate'); 
        var templatePlaceholder = dialogDom.find('#templatePlaceholder'); 
        templatePlaceholder.empty(); 
        templatePlaceholder.append(listTemplate); 

        var pagerControl = searchDom.find('#pagerControl'); 
        var pagerPlaceholder = dialogDom.find('#pagerPlaceholder'); 
        pagerPlaceholder.append(pagerControl); 

        var list = GenerateList(
         dialogDom, 
         $('<div></div>'), 
         searchObj, 
         Connection('MyUiService', 'GetObjects')); 
     } 

的GenerateList()方法創建了各種方法,包括那些從WCF獲取的對象數據的jQuery對象服務並將其綁定到模板(listTemplate)

PagerControl代碼還包含一個模板,該模板與listTemplate同時填充。

listTemplate和pager的代碼必須放在objectSelectorTemplate腳本之外,然後在稍後進行復制以防止在解析頁面以填充下拉列表時將其刪除。

所有上述工作在第一次打開對話框並從下拉列表中選擇一個項目時正常。可以毫無問題地更改表格中數據的頁面,但只要下拉列表中選定的項目發生更改,表格數據就不會再加載。如果我遍歷代碼,我可以看到append()(在LoadObjects方法中)在將listTemplate腳本插入到listPlaceholder時刪除它,這意味着當對話框再次加載表數據時,腳本不再那裏。爲了解決這個問題,我想追加一個克隆,而不是:

templatePlaceholder.append(listTemplate.clone()); 

這成功阻止listTemplate腳本被移除,然而,克隆副本包含的腳本標籤,但不是其內容,因此表中的數據仍然沒有得到加載。我尋遍SO,發現約翰Resig的,以this question迴應:

所以我改變了上面的代碼:

var listTemplateCopy = jQuery.extend({}, listTemplate); 
    templatePlaceholder.append(listTemplateCopy); 

這成功複製腳本標記及其內容listTemplateCopy但附加()刪除listTemplate以及作爲listTemplateCopy。起初,我認爲這是因爲擴展旨在將兩個(或更多)對象合併成一個對象,但是從John的響應和我在文檔中讀到的內容來看,它聽起來像擴展是你應該使用的創建一個jQuery對象的副本。

任何人都可以向我解釋究竟是怎麼回事,並建議上述解決方案?

一對夫婦的想法,我有是:

  • 移腳本標籤,從而只圍繞模板代碼。然後我可以有第二個模板代碼,而不需要追加它。綁定將通過綁定到下拉列表模板,然後綁定到表
  • 使用不同的方式來填充下拉列表而不是模板來簡化頁面並刪除「添加腳本」的「必要性」 ,因爲不會有一個腳本標籤圍繞整個地段

我想了解在執行這兩種方法之前,代碼正在做什麼。

回答

0

這絕不是一個優雅的答案,但實際上,這是IE8的腳本引擎及其前輩的失敗。如果你的項目有支持這些瀏覽器的需求,那麼代碼將會有點難看,jQuery也不會有多大的幫助。您會注意到,在代碼中第一次使用.clone()實際上在IE9,Firefox,Chrome和Safari中運行良好。請允許我解釋特定的困難。

您的需求是複製一個DOM對象。 $.extend()在這個實例中不合適,因爲它只會簡單地複製包裝DOM目標集的jQuery對象,而不是實際的DOM目標。這意味着包裝的新副本仍然具有相同的DOM元素,而不是追加目標副本,它會移動目標。出於這個原因,你使用.clone()的最初假設是正確的。代碼無法按預期運行的原因超出了您的控制範圍。

IE9校正與它的前輩的Node.cloneNode()方法,其中所述Node對象的innerHTML構件沒有在script元件的情況下保留了明顯的不足。這是jQuery的.clone()調用所使用的方法。執行一條線在IE8任何腳本塊上經典的JavaScript和更早的版本,就會發現儘可能多:

alert(document.getElementById("listTemplate").cloneNode(true).innerHTML); 

該警報將在所有其他主要瀏覽器的內容。在IE8及更低版本中並非如此。 「true」參數執行深度複製只是爲了證明一個觀點,但實際上這不是必需的,因爲script元素在其childNodes集合中沒有Nodes

解決方法是醜陋的,我不完全肯定它會按預期運行,因爲我沒有您的系統進行測試。您將不得不明確修改佔位符元素的innerHTML屬性。有一件事你可能會考慮包括一個defer屬性,它傾向於使腳本塊在IE中動態插入時表現得更好(參見MSDN - innerHTML Property at「當使用innerHTML插入腳本時,必須在腳本元素中包含DEFER屬性」)。它將使你的JavaScript看起來像下面這樣:

var listTemplate = searchDom.find('#listTemplate'); 
var myHtml = '<script defer="defer" type="text/x-jquery-tmpl">'; 
myHtml += listTemplate.html(); 
myHtml += "</script" + ">"; 

var templatePlaceholder = dialogDom.find('#templatePlaceholder'); 
templatePlaceholder.html(myHtml); 

我做了假設listTemplatetemplatePlaceholder是jQuery的對象,因此,如果我錯了,我道歉。但是,這裏的基本思想是將字符串的全部塊作爲HTML字符串構建,並使用您創建的字符串替換佔位符內的HTML。

我無法保證IE會正確解釋腳本塊,並使其可用於您的jQuery模板,但檢查我選擇的受害者佔位符的innerHTML確實顯示,至少它已被正確替換爲生成的腳本塊。

我很想知道這是否有效。

+0

謝謝:)我懷疑同樣的DOM元素被引用裏面使用擴展,但不確定。您的建議與將腳本添加到腳本中稍有調整(否則在下次載入表格數據時無法找到)有關。 –