добавить скрипт, содержащий HTML для шаблона JQuery - PullRequest
1 голос
/ 27 августа 2011

Пожалуйста, потерпите меня, поскольку я пытаюсь объяснить это, поскольку это несколько сложно, и я совершенно новичок в JQuery и пытаюсь обдумать это.

Моя команда и я работаем над WebParts для проекта SharePoint. Веб-часть содержит пользовательский элемент управления (SearchControl), который имеет ссылку для открытия диалогового окна (с помощью jquery ui), содержащего другой пользовательский элемент управления (SelectorControl).

SelectorControl содержит:

  • раскрывающийся список (objTemplates), который заполняется с помощью шаблонов JQuery
  • таблица, которая заполняется с помощью другого шаблона JQuery; и
  • текстовый ввод только для чтения, чтобы отобразить текущий выбранный элемент из таблицы

Код выбора селектора:

        <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 и проходя через выбранный в данный момент элемент в раскрывающемся списке.

Когда событие изменения запускается в раскрывающемся списке, вызывается LoadObjects:

            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 () создает объект JQuery с различными методами, включая методы, которые получают данные объектов из службы WCF и связывают их с шаблоном (listTemplate)

Код PagerControl также содержит шаблон, который заполняется одновременно с listTemplate.

Код для listTemplate и пейджера должен был быть помещен вне сценария objectSelectorTemplate, а затем скопирован позже, чтобы предотвратить его удаление при анализе страницы для заполнения раскрывающегося списка.

Все вышеперечисленное прекрасно работает при первом открытии диалогового окна и выборе элемента из раскрывающегося списка. Можно изменять страницы в данных таблицы без проблем, но как только выбранный элемент в раскрывающемся списке изменяется, данные таблицы больше не загружаются. Если я пошагово выполняю код, я вижу, что append () (в методе LoadObjects) удаляет скрипт listTemplate при вставке его в listPlaceholder, что означает, что когда диалог снова загружает данные таблицы, скрипт больше не является там. Чтобы обойти это, я попытался добавить клон вместо:

    templatePlaceholder.append(listTemplate.clone());

Это успешно предотвратило удаление сценария listTemplate, однако клонированная копия содержала теги сценария, но не его содержимое, поэтому данные таблицы по-прежнему не загружались. Я искал SO и нашел ответ Джона Ресига на этот вопрос :

Так что я изменил код выше:

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

Это успешно скопировало тег сценария и его содержимое в listTemplateCopy, но append () удаляет listTemplate, а также listTemplateCopy. Сначала я предположил, что это произошло потому, что extends предназначен для объединения двух (или более) объектов в один объект, но по ответу Джона и из того, что я прочитал в документации, это звучало так, как то, что вы должны использовать для расширения создать копию объекта jquery.

Может кто-нибудь объяснить мне, что именно происходит, и порекомендовать решение выше?

У меня была пара идей:

  • сдвигать теги скрипта так, чтобы они окружали только код шаблона. Тогда я мог бы иметь второй шаблонный код вместо того, чтобы добавлять его. Привязка выполняется привязкой к шаблону раскрывающегося списка, а затем к таблице
  • используйте другой способ для заполнения раскрывающегося списка, а не шаблон, чтобы упростить страницу и устранить «необходимость» добавления сценариев, так как не будет тега сценария, окружающего весь лот

Я хотел бы получить представление о том, что именно код делает в данный момент, прежде чем приступать к одному из этих подходов.

1 Ответ

0 голосов
/ 27 августа 2011

Это ни в коем случае не будет элегантным ответом, но по сути это сбой механизма сценариев IE8 и его предшественников. Если у вашего проекта есть требования, чтобы эти браузеры поддерживались, то код станет более уродливым, и jQuery не сильно поможет. Вы заметите, что ваше первое использование .clone() в коде на самом деле прекрасно работает в IE9, Firefox, Chrome и Safari. Позвольте мне объяснить особую сложность.

Ваше требование - реплицировать объект DOM. $.extend() неприемлемо в этом случае, так как он просто клонирует объект jQuery, который обертывает набор целей DOM, а не фактические цели DOM. Это означает, что новая копия оболочки по-прежнему имеет тот же целевой элемент (элементы) DOM, и вместо добавления копии цели (ей) она перемещает цель (и). По этой причине ваше первоначальное предположение об использовании .clone() было верным. Причина, по которой код не работает должным образом, находится вне вашего контроля.

IE9 исправляет явный недостаток с помощью метода Node.cloneNode() своих предшественников, когда элемент innerHTML объекта Node не сохраняется в случае элементов script. Этот метод используется вызовом jQuery .clone(). Выполнение строки классического JavaScript в любом блоке скриптов в IE8 и более ранних версиях покажет столько же:

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

Это предупреждение будет содержаться в любом другом крупном браузере. Не так в IE8 и ниже. Аргумент "true" выполняет глубокое копирование только для того, чтобы доказать свою точку зрения, но, честно говоря, в этом нет необходимости, поскольку у элементов script нет Nodes в его коллекции childNodes.

Обходной путь уродлив, и я не совсем уверен, что он будет работать так, как задумано, поскольку у меня нет вашей системы для тестирования. Вам придется явно изменить атрибут innerHTML вашего элемента-заполнителя. Одна вещь, которую вы могли бы рассмотреть, это включить атрибут defer, который имеет тенденцию к тому, чтобы блоки скриптов работали лучше при динамической вставке в IE (см. MSDN - свойство innerHTML at, "При использовании innerHTML для вставки скрипта необходимо атрибут DEFER в элементе script "). Ваш 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);

Я сделал предположение, что listTemplate и templatePlaceholder являются объектами jQuery, поэтому, если я ошибаюсь, я прошу прощения. Однако основная идея здесь заключается в буквальном построении полного блока скрипта в виде строки HTML и замене HTML внутри вашего заполнителя на созданную вами строку.

Я не могу гарантировать, что IE правильно интерпретирует блок скрипта и сделает его доступным для вашего шаблона jQuery, но проверка innerHTML заполнителя жертвы по моему выбору показала, что, по крайней мере, он был правильно заменен на сгенерированный скрипт-блок.

Мне было бы интересно узнать, работает ли это.

...