Introduction
In Sharepoint, there is no direct way to have a parent child relationship in lists. Here is one of the indirect ways to display nested list using Sharepoint. Let's take one example, Orders
and OrderDetails
. Orders
have multiple items, we refer to it as OrderDetails
. Our final result would be something like this:
To achieve this result, we use Sharepoint designer. Let's go step by step:
Step 1. Create lists Orders and OrderDetails (Site Action > Create > Custom List).
OrderDetails
list has Order lookup column, which refers to Title column of the Orders list.
Step 2. Open Sharepoint Site in Sharepoint Designer
Go to Start> Programs >Microsoft Office >Microsoft Office Sharepoint Designer 2007
Step 3. Open Page Where You Want to Add Nested List
Expand Orders list in Folder List pane(Task Panes > Folder List). Open AllItems.aspx page.
Step 4. Convert Listviewwebpart to Dataformwebpart
Right click on the “webpartpages:Listviewwebpart
” and select “convert to XSLT data view”.
It will convert list view web part to data form web part. Now, you can see text on top of web part as “webpartpages:Dataformwebpart
” instead of “webpartpages:Listviewwebpart
”.
Step 5. Click on Related Data sources > Link to another data source in Data Source Details pane (Task Panes > Data Source Details)
Step 6. Add OrderDetails list to Selected Data Source lists and click Next button
Step 7. Choose join option as link type and click Finish button
It will add OrderDetails
list to data source as linked data source.
Step 8. Add OrderDetails list code
Go to code view and search for <xsl:template name="dvt_1.rowview">
. At the end of the close tag, put the below code after </tr>
. Here, the data source is filtered on OrderID
(Parent
field is OrderNumber
).
<xsl:variable name="OrderNo" select="@OrderNumber" />
<xsl:variable name="SubRows"
select="/dsQueryResponse/OrderDetails/Rows/Row[@OrderID=$OrderNo]" />
<xsl:variable name="SubRowsCount" select="count($SubRows)" />
<xsl:if test="$SubRowsCount != 0">
<tr><th class="ms-vh" nowrap=""></th><th class="ms-vh" nowrap="">
Edit</th><th class="ms-vh" nowrap="">Product</th>
<th class="ms-vh" nowrap="">Description</th>
<th class="ms-vh" nowrap="">Price</th>
<th class="ms-vh" nowrap="">Quantity</th>
<th class="ms-vh" nowrap="" colspan="2"></th></tr>
</xsl:if>
<xsl:for-each select="$SubRows">
<tr>
<xsl:if test="position() mod 2 = 1">
<xsl:attribute name="class">ms-alternating</xsl:attribute>
</xsl:if>
<td> </td>
<td>
<xsl:choose>
<xsl:when test="ddwrt:IfHasRights(4)">
<a href=../OrderDetails/EditForm.aspx?ID={@ID}
onclick="javascript:this.href =
unescapeProperly(escape(this.href)); GoToLink(this);
return false;" target="_self">
<img border="0" alt="Edit"
src=http://www.codeproject.com/_layouts/images/edititem.gif />
</a></xsl:when>
<xsl:otherwise>
<xsl:text xmlns:ddwrt=
"http://schemas.microsoft.com/WebParts/v2/
DataView/runtime" ddwrt:nbsp-preserve="yes"
disable-output-escaping="yes">&nbsp;</xsl:text>
</xsl:otherwise>
</xsl:choose>
</td>
<td class="ms-vb"><xsl:value-of select="@Title" /></td>
<td class="ms-vb"><xsl:value-of select="@Desription" /></td>
<td class="ms-vb"><xsl:value-of select="@Price" /></td>
<td class="ms-vb"><xsl:value-of select="@Quantity" /></td>
<td colspan="2"></td>
</tr>
</xsl:for-each>
<tr>
<td class="ms-vb" colspan="5">
<a href=../OrderDetails/NewForm.aspx?OrderNumber={@OrderNumber}
onclick="javascript:this.href = unescapeProperly(escape(this.href));
GoToLink(this); return false;" target="_self">
Create a new Order Detail Entry...</a> </td>
</tr>
Step 9. Now we need to set value of Order Number column when user click on “Create a new Order Detail Entry...” link
Make this field disabled, so that the user cannot change its value.
Open NewForm.aspx page of OrderDetails
list. Add the below JavaScript code in PlaceHolderBodyAreaClass
.
<script type="text/javascript">
var qs = location.search.substring(1, location.search.length);
var args = qs.split("&");
var vals = new Object();
for (var i=0; i < args.length; i++) {
var nameVal = args[i].split("=");
var temp = unescape(nameVal[1]).split('+');
nameVal[1] = temp.join(' ');
vals[nameVal[0]] = nameVal[1];
}
setValueForFieldName("Order Number", vals["OrderNumber"]);
function setValueForFieldName(fieldName, value) {
if (value == undefined) return;
var theInput = getTagFromIdentifierAndTitle("input","",fieldName);
theInput.value = value;
theInput.disabled=true;
}
function getTagFromIdentifierAndTitle(tagName, identifier, title) {
var len = identifier.length;
var tags = document.getElementsByTagName(tagName);
for (var i=0; i < tags.length; i++) {
var tempString = tags[i].id;
if (tags[i].title == title && (identifier == "" ||
tempString.indexOf(identifier) == tempString.length - len)) {
return tags[i];
}
}
return null;
}
</script>
Step 10. Make Order Number column disabled in EditForm.aspx too, so that the user cannot change its value
Open EditForm.aspx page of OrderDetails
list. Add the below JavaScript code in PlaceHolderBodyAreaClass
.
<script type="text/javascript">
disableFields();
function getTagFromIdentifierAndTitle(tagName, identifier, title) {
var len = identifier.length;
var tags = document.getElementsByTagName(tagName);
for (var i=0; i < tags.length; i++) {
var tempString = tags[i].id;
if (tags[i].title == title && (identifier == "" ||
tempString.indexOf(identifier) == tempString.length - len)) {
return tags[i];
}
}
return null;
}
function disableFields() {
var theInput = getTagFromIdentifierAndTitle("input","","Order Number");
theInput.disabled=true;
}
</script>
Step 11. Replace Edit and Display URL
Replace <xsl:param name="URL_EDIT"/>
with <xsl:param name="URL_EDIT">\u002fLists\u002fOrder\u002fEditForm.aspx</xsl:param>
and <xsl:param name="URL_DISPLAY" />
with <xsl:param name="URL_DISPLAY">\u002fLists\u002fOrder\u002fDispForm.aspx</xsl:param>
in AllItems.aspx page.
All done, you can make changes in XSLT or JavaScript as per your requirements.
History
- 21st July, 2010: Initial post