Salut,
J'ai récemment discuté avec une personne qui souhaitait afficher des données dynamiques provenant d'une DB externe à partir du displaypattern d'un custom field.
Comme vous le savez, le displaypattern est utilisé pour décrire comment une colonne doit s'afficher en mode liste.
Pour plus d'infos sur les patterns, vous pouvez consulter ce lien
Ces patterns ne sont pas tous simples à utiliser et le but de ce billet n'est pas de les expliquer mais simplement de faire un POC démontrant la possibilité d'utiliser de l'AJAX dans les patterns CAML.
Je l'ai juste fait pour le fun et n'ai pas encore eu à le réaliser dans un projet.
D'ailleurs si cela vous arrive, pensez à utiliser le BDC si possible...
Bon, voici néanmoins le scénario du POC
Disons que vous avez une liste SharePoint dans laquelle vous avez un custom field qui stocke l' ID d'un enregistrement de DB. Vous voulez offrir aux utilisateurs la possibilité de recevoir le libellé correspondant à cet ID de manière dynamique comme illustré ci-dessous
Comme vous pouvez le constater, J'ai les IDs qui viennent de la DB et je peux récupérer les libellés correspondants en cliquant sur l'image à côté des IDs.
Pour pouvoir obtenir ce résultat, vous devez faire ceci:
- Developper un custom field
- Developper le CAML du fichier FLDTYPES_xxx.xml associé à votre custom field et dans lequel vous devez inclure le code javascript
- Developper une page server ou utiliser un web service qui retourne une réponse XML aux requêtes AJAX.
Ceci fait, en cliquant sur une image, vous obtiendrez ceci:
Voici le code
Le custom field
C'est un simple POC qui utilise un SPFieldText hyper basique, juste cette classe suffit
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
namespace AjaxRawField
{
public class AjaxRawView : SPFieldText
{
public AjaxRawView(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
}
public AjaxRawView(Microsoft.SharePoint.SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
}
}
}
La page serveur
Rappelez-vous qu'il s'agit juste d'un POC, donc pour simplifier les choses, je n'ai pas été chercher les données d'une DB..Je ne fais que renvoyer du XML mais avec un peu d'imagination, celui-ci pourrait être généré après une query DB.
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Threading" %>
<script runat="server">
protected override void Render(HtmlTextWriter writer)
{
try
{
Thread.Sleep(1000);
Response.ContentType = "text/xml";
int Id = Convert.ToInt16(Request.QueryString["Id"]);
List<string> Ids = new List<string>();
for (int i = 0; i < 10; i++)
{
Ids.Add(string.Format("Label {0}",i.ToString()));
}
Response.Write(string.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Label Text=\"{0}\"/></Root>",Ids[Id]));
}
catch
{
Response.Write("<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Label Text=\"Not found\"/></Root>");
}
}
</script>
Si vous copiez/collez ce code dans une page aspx et la déployez dans le répertoire LAYOUTS, ça devrait suffire.
Le fichier CAML
C'est ici que ça se complique!
L'idée est d'écrire les fonctions AJAX dans le headerpattern du custom field et de les appeler dans le displaypattern
<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
<FieldType>
<Field Name="TypeName">AjaxRawField</Field>
<Field Name="ParentType">Text</Field>
<Field Name="TypeDisplayName">AjaxRawField</Field>
<Field Name="TypeShortDescription">AjaxRawField</Field>
<Field Name="UserCreatable">TRUE</Field>
<Field Name="ShowInListCreate">TRUE</Field>
<Field Name="ShowInSurveyCreate">TRUE</Field>
<Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
<Field Name="ShowInColumnTemplateCreate">TRUE</Field>
<Field Name="FieldTypeClass">AjaxRawField.AjaxRawView, AjaxRawField,Version=1.0.0.0, Culture=neutral, PublicKeyToken=a17af6dda41cb365</Field>
<Field Name="MaxLength">2000</Field>
<RenderPattern Name="HeaderPattern">
<Switch>
<Expr>
<Property Select='Filterable'/>
</Expr>
<Case Value="FALSE"> </Case>
<Default>
<Switch>
<Expr>
<GetVar Name='Filter'/>
</Expr>
<Case Value='1'>
<HTML><![CDATA[<SELECT ID="diidFilter]]></HTML>
<Property Select='Name'/>
<HTML><![CDATA[" TITLE=]]></HTML>
<HTML>"$Resources:spscore,BusinessDataField_Filterby;</HTML>
<Property Select='DisplayName' HTMLEncode='TRUE'/>
<HTML><![CDATA[" OnChange='FilterField("]]></HTML>
<GetVar Name="View"/>
<HTML><![CDATA[",]]></HTML>
<ScriptQuote>
<Property Select='Name' URLEncode="TRUE"/>
</ScriptQuote>
<HTML>
<![CDATA[,this.options[this.selectedIndex].value, this.selectedIndex, 0);' dir="]]>
</HTML>
<Property Select="Direction" HTMLEncode="TRUE"/>
<HTML><![CDATA[">]]></HTML>
<FieldFilterOptions BooleanTrue="$Resources:spscore,BusinessDataField_Yes;"
BooleanFalse="$Resources:spscore,BusinessDataField_No;"
NullString="$Resources:spscore,BusinessDataField_Empty;"
AllItems="$Resources:spscore,BusinessDataField_All;"></FieldFilterOptions>
<HTML><![CDATA[</SELECT><BR>]]></HTML>
</Case>
</Switch>
</Default>
</Switch>
<Switch>
<Expr>
<Property Select='Sortable'/>
</Expr>
<Case Value="FALSE">
<Property Select='DisplayName' HTMLEncode="TRUE"/>
</Case>
<Default>
<Switch>
<Expr>
<GetVar Name='SortDisable'/>
</Expr>
<Case Value='TRUE'>
<Property Select='DisplayName' HTMLEncode="TRUE"/>
</Case>
<Default>
<HTML><![CDATA[<A ID="diidSort]]></HTML>
<Property Select='Name'/>
<HTML>
<![CDATA[" TITLE=]]>
</HTML>
<HTML>"$Resources:spscore,BusinessDataField_Sortby;</HTML>
<Property Select='DisplayName' HTMLEncode='TRUE'/>
<HTML><![CDATA[" SORTINGFIELDS="]]></HTML>
<FieldSortParams/>
<HTML><![CDATA[" HREF="javascript:" OnClick='javascript:SubmitFormPost("]]></HTML>
<ScriptQuote NotAddingQuote="TRUE">
<PageUrl/>
<HTML><![CDATA[?]]></HTML>
<FieldSortParams/>
</ScriptQuote>
<HTML>
<![CDATA[");javascript:return false;'>]]>
</HTML>
<Property Select='DisplayName' HTMLEncode="TRUE"/>
<HTML><![CDATA[</A><IMG SRC="]]></HTML>
<FieldSortImageURL/>
<HTML><![CDATA[" ALT=]]></HTML>
<Switch>
<Expr>
<GetVar Name='SortDir'/>
</Expr>
<Case Value='Asc'>
<HTML>$Resources:spscore,BusinessDataField_Asc;</HTML>
</Case>
<Case Value='Desc'>
<HTML>$Resources:spscore,BusinessDataField_Desc;</HTML>
</Case>
<Default>
<HTML>""</HTML>
</Default>
</Switch>
<HTML><![CDATA[ BORDER=0>]]></HTML>
</Default>
</Switch>
</Default>
</Switch>
<HTML><![CDATA[<IMG SRC="]]></HTML>
<FieldFilterImageURL/>
<HTML><![CDATA[" BORDER=0 ALT=]]></HTML>
<HTML>""</HTML>
<HTML><![CDATA[>]]></HTML>
<HTML>
<![CDATA[
<script language="javascript">
ReturnedIds = new Array();
HttpObject = null;
function DoQuery(Id)
{
if(HttpObject == null)
{
if (window.XMLHttpRequest)
{
HttpObject = new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
HttpObject = new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
}
HttpObject.DOMTarget = document.getElementById("__"+Id);
if(HttpObject.DOMTarget && HttpObject.DOMTarget.innerHTML.indexOf("-")==-1)
{
HttpObject.DOMTarget.innerHTML = HttpObject.DOMTarget.innerHTML + "- waiting for server...";
HttpObject.open("GET", "/_layouts/GetTitles.aspx?id="+Id, true);
HttpObject.setRequestHeader("Content-Type","text/xml; charset=utf-8");
HttpObject.setRequestHeader("Host", "localhost");
readyStateChangeHandler = AjaxAnswer;
HttpObject.onreadystatechange = readyStateChangeHandler;
HttpObject.send();
}
}
function AjaxAnswer()
{
if (HttpObject.readyState==4 && HttpObject.status==200)
{
var xml = HttpObject.responseXML;
if (xml.documentElement)
{
var rows = xml.documentElement.getElementsByTagName("z:Label");
if (rows.length==0)
{
rows = xml.documentElement.getElementsByTagName("Label");
}
if (rows.length > 0)
{
for (var i = 0; i < rows.length; i++)
{
if (rows[i].getAttributeNode("Text")!=null)
{
HttpObject.DOMTarget.innerHTML = parseInt(HttpObject.DOMTarget.innerHTML) + "-" +rows[i].getAttributeNode("Text").nodeValue;
}
}
}
}
}
}
</script>
]]>
</HTML>
</RenderPattern>
<RenderPattern Name="DisplayPattern">
<HTML><![CDATA[<table><tr><td id="__]]></HTML>
<Column HTMLEncode="TRUE"/>
<HTML><![CDATA[">]]></HTML>
<Column HTMLEncode="TRUE"/>
<HTML><![CDATA[</td><td><img onclick="DoQuery(']]></HTML>
<Column HTMLEncode="TRUE"/>
<HTML><![CDATA[')" src="_layouts/images/BDUPDATE.GIF"/></td></tr></table>]]></HTML>
</RenderPattern>
</FieldType>
</FieldTypes>
------------------------------------------------------------------
Voilà c'est fait! Simple non?
Déployez ce fichier XML dans le répertoire XML du 12 et vous aurez une nouvelle colonne vous permettant d'effectuer du rendering dynamique en mode liste.