Please bear with me as I try to explain this as it's somewhat complicated and I am totally new to JQuery and trying to get my head around it.
My team and I are working on WebParts for a SharePoint project. The WebPart contains a user control (SearchControl), which has a link to open a dialog (using jquery ui) that contains another user control (SelectorControl).
SelectorControl contains:
- a drop-down list (objTemplates) that is populated using JQuery Templates
- a table that is populated using another JQuery Template; and
- a readonly text input to display the currently selected item from the table
SelectorControl code:
<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>
The drop-down list is populated just before the dialog is created using data retrieved from a WCF service that's then bound to the first template.
A 'change' event is bound to the drop-down list using live to populate the table (second template) by calling a WCF Service and passing through the currently selected item in the drop-down list.
When the change event is triggered on the drop-down list, LoadObjects is called:
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'));
}
The GenerateList() method creates a JQuery object with various methods including ones that get the objects data from a WCF service and bind it to the template (listTemplate)
The PagerControl code also contains a template, which is populated at the same time as listTemplate.
The code for listTemplate and the pager had to be put outside of the objectSelectorTemplate script and then copied in later to prevent it from being removed when the page is parsed for the populating of the drop-down list.
All of the above works fine the first time the dialog is opened and an item is selected from the drop-down list. It is possible to change pages within the data in the table without any problem but as soon as the selected item in the drop-down list changes, the table data is no longer loaded. If I step through the code, I can see that append() (in the LoadObjects method) removes the listTemplate script when it inserts it into listPlaceholder, which means that when the dialog goes to load the table data again, the script is no longer there. To get around this, I tried appending a clone instead:
templatePlaceholder.append(listTemplate.clone());
This successfully prevented the listTemplate script from being removed, however, the cloned copy contained the script tags but not its contents so the table data still didn't get loaded. I searched through SO and found John Resig's response to this question:
So I changed the above code to:
var listTemplateCopy = jQuery.extend({}, listTemplate);
templatePlaceholder.append(listTemplateCopy);
This successfully copied the script tag and its contents to listTemplateCopy but append() removes listTemplate as well as listTemplateCopy. At first I assumed this was because extend is intended for merging two (or more) objects into a single object but from John's response and from what I've read in the documentation, it sounded like extend is what you're supposed to use to create a copy of a jquery object.
Can anyone explain to me what exactly is going on and recommend a solution to the above?
A couple of ideas I had was to:
- shift the script tags to only surround the template code. I could then have the second template code in place rather than needing to append it. Binding would be done by binding to the drop-down list template then to the table
- use a different manner to populate the drop-down list rather than a template to simplify the page and remove the "necessity" to have scripts being appended, as there wouldn't be a script tag surrounding the whole lot
I would like to gain an understanding of exactly what the code is currently doing though before pursuing either of those approaches.