Wednesday, December 21, 2011

SharePoint Metadata field. Part 1: Web Services in DisplayPattern


Once I was faced with the necessity of storing data of lists in… lists.

The first idea was to use standard set of SharePoint data types but I had to refuse it because it wasn’t a proper decision for solving such problems.

Text (one line, multiline)
Value: List ID
Disadvantages:
  • not user friendly
  • irrelevant data
Absurdities occurring: "Information about goods is in list with ID {30431E5A-7D75-438f-B786-716690DBDAE2}"

Hyperlink or picture
Value: List URL and List Title
Disadvantages:
  • multiple values are not used
  • irrelevant data
Absurdities occurring: "Employees list is already available via another URL, Contractors list is already renamed in Clients list, and there is already no library with goods descriptions at all."

Business data
Value: List information from SharePoint database
Disadvantage: Lack of data type in WSS

Absurdities occurring: "We use WSS and know nothing about business-data."

It looks like that proper decision will be creation of customizable data type. Technology of customable field types creation is described in Custom Field Types. I’d like to get a closer look at two key points in the decision – displaying field values in Render Patterns in FLDTYPES_*.XML file:
  • DisplayPattern (keystone in custom field types creation)
  • HeaderPattern  (filtering field values of custom field types in ListViewWebPart)

The first and the most important point in this decision is DisplayPattern named RenderPattern. It’s quite reasonable to display field value(s) by means of web-link(s) to list(s), which value is set this field (further used in singular) in this pattern.  The URL of the displayed web-link will be the URL of the default view of the list, and the link text will be the current list title.

It’s obvious that CAML markup isn’t enough for such a problem. It’s better to use SharePoint Web Services from JavaScript in order not to overdose the markup in the pattern. You can get information about the List via SharePoint Web Services using GetList method of the standard Lists.asmx web service. A JavaScript function is given below. It returns list title and its URL of the default view of the list via this method:

function GetListData(weburl, listName) {
    // weburl – the absolute URL for the Web site
    // listName - list GUID
    var resArray = new Array(2);
    var a = new ActiveXObject("Microsoft.XMLHTTP");
    if (a == null) return null;
    a.Open("POST", weburl + "/_vti_bin/Lists.asmx", false);
    a.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    a.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetList");
    var d = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
            + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
            + "<soap:Body>"
            + "<GetList xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">"
            + "<listName>" + listName + "</listName>"
            + "</GetList>"
            + "</soap:Body>"
            + "</soap:Envelope>";
    a.Send(d);
    if (a.status != 200) {
        resArray[0] = "err";
    }
    else {
        resArray[0] = a.responseXML.selectSingleNode("//List").getAttribute("DefaultViewUrl");
        resArray[1] = a.responseXML.selectSingleNode("//List").getAttribute("Title");
    }
    return resArray;
}

Looking at the definition of the function we understand that the field value must contain list GUID and URL of the web which contains the list itself. It can look like that: [Web URL][Delimiter][List ID].

An estimated function (because it depends on personal needs) of displaying field single value in DisplayPattern:

function GetListDataInDiv(siteurl, val, divid) {
    // siteurl – the full URL to the root Web site of the site collection
    // val – field value
    // divid – id of <div> element for view of field value
    var resStr = "";
    var sVals = val.split(';'); // ; - delimiter of  WebUrl and ListID values
    // get data about list
    var res = GetListData(sVals[0], sVals[1]);
    if (res[0] != "err") {
        resStr = "<tr>";
        resStr += "<td Class=\"ms-vb2\">" + GetWebTitle(sVals[0]) + "</td>";
        resStr += "<td Class=\"ms-vb2\"><a href=\"" + res[0] + "\">" + res[1] + "</a></td>";
        resStr += "</tr>";
    }
    var div = document.getElementById(divid);
    if (resStr.length > 0) {
        // view field as a table
        div.innerHTML = "<table class=\"ms-listviewtable\"><tr><th> " + GetResLabelTitle("MetaControl_WebColumnTitle") + "</th><th> " + GetResLabelTitle("MetaControl_ContentTypeColumnTitle") + " </th></tr>" + resStr + "</table>";
    }
    return resStr;
}

GetResLabelTitle function (which is used the function given) returns value via specified key of data which are stored in .resx-file. Its realization resolves into creating of a Custom Web Service and calling it from JavaScript, it’s similar to Lists.asmx. web service. GetWebTitle function returns current web title and it’s similar to GetListData by using Webs.asmx web service and GetWeb method.

When a web page is completely displayed it’s necessary to call GetListDataInDiv function than it will display the data table of field value correctly. Here it’s better to use "onload" event of "iframe" tag.

So RenderPattern named DisplayPattern will look like:
<RenderPattern Name="DisplayPattern">
  <HTML><![CDATA[<iframe height="0" width="0" onload="GetListDataInDiv(&quot;]]></HTML>
  <HttpVDir/>
  <HTML><![CDATA[&quot;, &quot;]]></HTML>
  <Column/>
  <HTML><![CDATA[&quot;, &quot;div_div]]></HTML>
  <Property Select="Name"/>
  <Field Name="ID"/>
  <HTML>
    <![CDATA[&quot;);"></iframe>]]>
  </HTML>
  <HTML>
    <![CDATA[<div id="div_div]]>
  </HTML>
  <Property Select="Name"/>
  <Field Name="ID"/>
  <HTML>
    <![CDATA["></div>]]>
  </HTML>
</RenderPattern>

The result of activity is looks like:






In the second part of the article we will consider displaying of fields values in RenderPattern named HeaderPattern, and field values filtering in ListViewWebPart. However has been already “released”. All JavaScript functions will be stored in one file – Metadata.js, and it’s quite reasonable to give a link to it in this particular DislplayPattern.
<RenderPattern Name="HeaderPattern">
 <HTML><![CDATA[<script src="/_layouts/Metadata.js"></script>]]></HTML>
</RenderPattern> 

P.S.: See also - SharePoint Extended lookup field. Part 2: Value display in ListViewWebPart using jQuery+JSON.

Russian version - SharePoint: Столбцы метаданных. Часть 1: Использование веб-служб в DisplayPattern.

No comments:

Post a Comment