Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

SharePoint List Parent / Child Relationship

3.71/5 (6 votes)
23 Sep 2010CPOL2 min read 75.5K   1K  
SharePoint Custom Field Type: ParentChildrenField for parent/child list relationships.

Introduction

Parent-child relationship pattern is very common in the real world. In SharePoint, it is represented with two SharePoint lists, linked with a Lookup Field contained in the child list. That way, the Parent-Child relationship is established between the Lists.

We need a way to present child items in Parent List Forms (DisplayForm.aspx, EditForm.aspx, NewForm.aspx). For that purpose, I created a SharePoint Custom Field Type: "ParentChildrenField".

Description

To make a custom tab-dialog navigation instead of the standard SharePoint site top navigation, I created two SharePoint lists: Tabs and Sub-Tabs. I created the site column "Parent Tab", type Lookup on the table Tabs, showing the column Title. That column is added to the "Sub-Tabs" list.

Parent-Child Relationship

Create "My Child Items" Field

To present child items (sub-tabs) in the Tab Forms (Display, Edit, and New), I created a new SharePoint Site Column "My Child Items", type of the previously defined "ParentChildrenField". That column is added to the parent list "Tabs". Generally, it is much better to add columns to the list Content Types instead of directly to the List.

Parent-Child Relationship

Source Code

C#
public class ParentChildrenFieldControl : TextField
{
    int NumOfChildren = 0;
    LiteralControl literalCtrl;
    SPList childList = null;
    string listID = SPContext.Current.List.ID.ToString();
    HyperLink linkAddNew = new HyperLink();
    
    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        if (this.ControlMode == SPControlMode.Display ||
            this.ControlMode == SPControlMode.Edit ||
            this.ControlMode == SPControlMode.New)
        {
            literalCtrl = new LiteralControl();
            base.Controls.Add(literalCtrl);
            base.Controls.Add(linkAddNew);
        }
    }


    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        string childListname = this.Field.GetCustomProperty("ChildListName").ToString();
        childList = SPContext.Current.Web.Lists[childListname];
        StringBuilder sb = new StringBuilder();
        SPQuery query = new SPQuery(childList.DefaultView);
        query.Query = string.Format(@"
        <Where>
           <Eq>
              <FieldRef Name='{0}' LookupId='true' />
              <Value Type='Integer'>{1}</Value>
           </Eq>
        </Where>", LookupField.InternalName, this.Item.ID.ToString()); 
            sb.Append(childList.RenderAsHtml(query));

        literalCtrl.Text = sb.ToString();

        // Add new
        linkAddNew.Text = "Add New";
        string navigateUrl = string.Format("/NewForm.aspx?{0}={1}&Source={2}", 
                      SPEncode.UrlEncode(LookupField.Title), 
                      SPContext.Current.ListItem.ID.ToString(), 
                      SPEncode.UrlEncode(this.Page.Request.Url.ToString()));
        linkAddNew.NavigateUrl = childList.RootFolder.ServerRelativeUrl + navigateUrl; 
    }

    SPField _LookupField = null;
    SPField LookupField    
    {
        get {
            if (_LookupField == null) 
            {
                foreach (SPField field in childList.Fields) 
                {
                    if (field is SPFieldLookup && 
                        ((SPFieldLookup)field).LookupList == listID) 
                    {
                        _LookupField = field;
                        break;
                    }
                }
            }
            return _LookupField;
        }
    }

    protected override void Render(HtmlTextWriter output)
    {
        literalCtrl.RenderControl(output);
        // Add New link
        if (this.ControlMode == SPControlMode.Display ||
            this.ControlMode == SPControlMode.Edit)
            linkAddNew.RenderControl(output);
    }

    public override void UpdateFieldValueInItem()
    {
        this.EnsureChildControls();
        this.Value = NumOfChildren;
        this.ItemFieldValue = this.Value;
    }
}

Add a New Child Item

When the user adds new child items, we want ot automatically select the item of the "Parent Tab" dropdown list in the NewForm.aspx form. That's why we add the Lookup Field Name and Value in the request query string: "NewForm.aspx?Parent%20Tab=1&Source=..." .

Parent-Child Relationship

Put the following JavaScript block to the Child List NewForm.aspx. The best place is in "PlaceHolderBodyAreaClass".

JavaScript
<script type="text/javascript">
var qs = location.search.substring(1, location.search.length);  
var nameVal = qs.split("&")[0].split("=");  
SetLookupFieldValue(unescape(nameVal[0]), nameVal[1]);
    
function SetLookupFieldValue(fieldName, val) {
    var theSelect = getTagFromIdentifierAndTitle("select", 
                    "Lookup", fieldName);
    if (theSelect != null) {
        theSelect.value = val;
        return;
    }
    // if theSelect is null, 
    // it means that the target list has more than 20 items, 
    // and the Lookup is being rendered with an input element
    var theInput = getTagFromIdentifierAndTitle("input", 
                                                "", fieldName);
    theInput.value = val;
}

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>

Installation

The Solution Package "ParentChildListRelationship.wsp" was developed using Visual Studio Extensions VSeWSS v1.3. Open "Setup.bat" and set your Site and Web URLs:

set DefaultWebUrl=http://YourWeb 
set DefaultSiteUrl=http://YourSite

To install, run setup.bat. To uninstall, run setup.bat -u.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)