пятница, 22 июня 2012 г.

SharePoint: Расширенная подстановка - Вывод значений в ListViewWebPart с использованием jQuery + JSON

В своей самой первой статье блога я рассказывал об отображении значений столбцов в шаблоне отображения полей (RenderPattern) DisplayPattern  с применением веб-служб и JavaScript. Этот способ довольно неплох, за исключением одного НО - при больших объемах отображаемых данных, производительность падает! Это связано с тем, что каждый раз совершается вызов веб-службы, если значение столбца не пусто, и собственно парсится wsdl ответ. Возможно, этот способ вывода значений и удовлетворил конечного пользователя при данном типе столбца (вряд ли столбец метаданных потребуется широкой аудитории), но с типом «Расширенная подстановка» данный финт бы не прошел.

Конечно, первое наперво, что приходит в голову для автоматизации – вызов единожды веб-службы с передачей массива неповторяющиеся значений столбца. Ну, а вместо XML лучше выбрать другой формат данных, без лишних сложностей. Одним из лучших способов выбрать необходимые элементы на странице HTML является использование jQuery. А передавать и получать данные лучше всего при выборе данного фреймворка в формате JSON, тем более что для работы с ним в .NET Framework 3.5 SP1 имеются необходимые метаданные.

Поскольку вызов веб-службы будет происходить единожды, то лучше сделать это нужно по событию элемента, находящегося  в шаблоне отображения полей HeaderPattern. Таким будет являться опять же элемент iframe с событием onload. Ниже приведена часть кода HeaderPattern, относящегося к данной задаче.
<RenderPattern Name="HeaderPattern">
  <HTML><![CDATA[<script src="/_layouts/jQuery/jquery-1.6.4.js"></script>]]></HTML>
  <HTML><![CDATA[<script src="/_layouts/jQuery/json2.js"></script>]]></HTML>
  <HTML><![CDATA[<script src="/_layouts/ExtLookup.js"></script>]]></HTML>
  <HTML><![CDATA[<iframe id="Header]]></HTML>
  <List/>
  <Property Select="Name"/>
  <HTML><![CDATA[" height="0" width="0" onl oad="GetExtValueAJAX(&quot;div_]]></HTML>
  <List/>
  <Property Select="Name"/>
  <HTML><![CDATA[&quot;, &quot;]]></HTML>
  <HttpVDir/>
  <HTML>
    <![CDATA[&quot;, &quot;]]>
  </HTML>
  <List/>
  <HTML>
    <![CDATA[&quot;, &quot;]]>
  </HTML>
  <Property Select="Name"/>
  <HTML>
    <![CDATA[&quot;);"></iframe>]]>
  </HTML>
</RenderPattern>
Файл, json2.js, JavaScript реализацию JSON-парсера можно взять, предварительно с ним познакомившись из JSON in JavaScript. Сам ExtLookup.js – скрипт, содержащий в себе реализацию метода GetExtValueAJAX. Код его приведен ниже. 
function GetExtValueAJAX(divname, siteurl, listid, fieldname) {
    $(document).ready(function () {
        // инициализация массивов для отбора неповторяющимся значений
        var mass = [];
        var vass = [];
        // замена мета-символов в селекторе
        divname = divname.replace("{""\\{").replace("}""\\}");
        // выборка элементов div, относящихся к столбцу
        var divs = $('div[id^=' + divname + ']').toArray();
        $.each(divs, function() {
            if (this.extvalue != "") {
                // заполенение массива mass неповторяющимися значения столбца (значениями атрибута extvalue)
                if ($.inArray(this.extvalue, vass) == -1) {
                    vass.push(this.extvalue);
                    mass.push({ "Value"this.extvalue, "Display""" });
                }
                    
            }
        });
        // вызов веб-службы для получения 
        $.ajax({
            type: "POST",
            url: siteurl + "/_vti_bin/WSJSONExtLookup.asmx/GetExtLookupValue",
            // передача данных в виде строки объектов в формате JSON
            dat a: "{ value:'" + JSON.stringify(mass) + "', listID: '" + listid + "', fieldName: '" + fieldname + "'}",
            contentType: "application/json; charset=utf-8",
            success: function ExtValueSuccess(response) {
                // получение результата
                var extVals = eval('(' + response.d + ')');
                $.each(divs, function() {
                    if (this.extvalue != "") {
                        // замена содержимого эелемента div соответствующим значению столбца HTML-кодом
                        $(this).html(RenderExtLookupJSON(this.extvalue, extVals));
                    }
                });
            },
            dataType: "json",
            failure: ExtValueCallFailed
        });
    });
    return 0;
}
 
function ExtValueCallFailed() {
    // вывод ошибки 
}
 
function RenderExtLookupJSON(val, extVals) {
    var res = "";
    $.each(extVals, function () {
        if (this.Value == val) {
            res += this.Display + "<br/>";
        }
    });
    return res;
}
В начале отбираются неповторяющиеся значения атрибутов extvalue элементов div, относящихся к данному столбцу, а потом передаются в качестве параметра веб-службе, которая их обрабатывает и выдает значения для отображения также в формате JSON. И затем по соответствующим значениям атрибута extvalue заменяется содержимое элементов div.

Полную ясность понимания работы скрипта даст невозможно без описания шаблона отображения полей DisplayPattern. Именно в нём задаются значения ID элементов div отображения значения столбца, здесь же прописывается атрибут extvalue с соответствующим значением самого столбца. 
<RenderPattern Name="DisplayPattern">
  <HTML>
    <![CDATA[<div id="div_]]>
  </HTML>
  <List/>
  <Property Select="Name"/>
  <Field Name="ID"/>
  <HTML>
    <![CDATA[" extvalue="]]>
  </HTML>
  <Column/>
  <HTML>
    <![CDATA["></div>]]>
  </HTML>
</RenderPattern>
Серверная часть - код веб-службы приведен ниже. Здесь приведены только фрагменты кода по главным ключевым моментам, а именно классу DataContractJsonSerializer для работы с форматом JSON и описание класса, инкапсулирующего данные JSON. Сама реализация вывода значений в формате HTML зависит от фантазии разработчика. 
[System.Runtime.Serialization.DataContract]
public class ExtLookupValueJSON
{
    public ExtLookupValueJSON() { }
    public ExtLookupValueJSON(string value, string display) { this.Value = value; this.Display = display; }
 
    [System.Runtime.Serialization.DataMember(Name = "Value")]
    public string Value { getset; }
 
    [System.Runtime.Serialization.DataMember(Name = "Display")]
    public string Display { getset; }
}
 
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WSJSONExtLookup : WebService
{
    public WSJSONExtLookup() { }
 
    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public string GetExtLookupValue(string value, string listID, string fieldName)
    {
        List<ExtLookupValueJSON> list=new List<ExtLookupValueJSON>();
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(list.GetType());
        using (MemoryStream ms = new MemoryStream(Encoding.Default.GetBytes(value)))
        {
            list = (List<ExtLookupValueJSON>)serializer.ReadObject(ms);
            ms.Close();
        }
        [...]
        string jsonString = "";
        using (MemoryStream ms = new MemoryStream())
        {
            serializer.WriteObject(ms, res);
            jsonString = Encoding.UTF8.GetString(ms.ToArray());
            ms.Close();
        }
        return jsonString;
    }
}
Единственным недостатком данного решения является открытая визуальность вывода значений. Как известно, jQuery срабатывает, когда страница полностью загружена. Так вот после её загрузки конечный пользователь может наблюдать последовательный вывод элементов, относящихся к столбцам данного типа. По времени занимает это считанные секунды и гораздо приятней наблюдать последовательную загрузку страницы, нежели ждать её полного появления при эффекте зависания.

English version - SharePoint Extended lookup field. Part 2: Value display in ListViewWebPart using jQuery+JSON

Комментариев нет:

Отправить комментарий