Wednesday, February 14, 2007

How to disable fields on EditForm.aspx. WSS 3.0 version.

I had a task to disable or make read-only some of a SharePoint list fields. I did not wanted to do much development and found some very good solutions for WSS 2.0: How can I make a field read-only? How can JavaScript’ers create custom EditForm without understanding CAML and .NET !

But in case with WSS3.0 these solutions do not work properly because it is very hard to calculate edit element name or id and in my solution I use title attribute of input or select elements generated by ListFormWebPart web part:

<SELECT 
id=ctl00_m_g_4cfb4dc8_9323_4849_bbfb_95af4cc4f470_ctl00_ctl02_ctl00_ctl01_ctl00_ctl00_ctl02_ctl00_ctl00_ctl04_ctl00_Lookup 
title=Company 
name=ctl00$m$g_4cfb4dc8_9323_4849_bbfb_95af4cc4f470$ctl00$ctl02$ctl00$ctl01$ctl00$ctl00$ctl02$ctl00$ctl00$ctl04$ctl00$Lookup> 
<OPTION value=0 selected>(None)</OPTION> 
<OPTION value=6>Transfield Services</OPTION>
</SELECT>

So I created a JavaScript function and placed it after the ListFormWebPart:

<SCRIPT language=javascript>
/// <summary>
/// Disables EditForm field for the specified column title
/// </summary>
function DisableField(title)
{
    for(var i = 0; i < document.all.length; i++)
    {
        var el = document.all[i];
        // find html element with specified title
        if(el.title == title)
        {
            el.disabled = true; // disable
            break;
        }
    }
}
DisableField("Company");
DisableField("Site/Industry");
</SCRIPT>

And these two fields are disabled for editing.

But this ListFormWebPart web part is a tricky thing and creates dropdown lists in different way depending on amount of their items:

Drop down list 1:

<SELECT 
id=ctl00_m_g_4cfb4dc8_9323_4849_bbfb_95af4cc4f470_ctl00_ctl02_ctl00_ctl01_ctl00_ctl00_ctl02_ctl00_ctl00_ctl04_ctl00_Lookup 
title=Company 
name=ctl00$m$g_4cfb4dc8_9323_4849_bbfb_95af4cc4f470$ctl00$ctl02$ctl00$ctl01$ctl00$ctl00$ctl02$ctl00$ctl00$ctl04$ctl00$Lookup> 
<OPTION value=0 selected>(None)</OPTION> 
<OPTION value=6>Transfield Services</OPTION>
</SELECT>

Drop down list 2:

<INPUT class=ms-lookuptypeintextbox 
onkeypress=HandleChar() 
id=Text1 
onkeydown=HandleKey() title=Site/Industry 
onfocusout=HandleLoseFocus() 
onchange=HandleChange() 
value="Transfield Services Generic Documents" 
name=ctl00$m$g_4cfb4dc8_9323_4849_bbfb_95af4cc4f470$ctl00$ctl02$ctl00$ctl01$ctl00$ctl00$ctl03$ctl00$ctl00$ctl04$ctl00$ctl01 
choices="ACT Housing TFM Contracts232ADI Alliance - FFG Refit &amp; Upgrade Project6...<here goes a very long list of choices>" 
match="" optHid="SPSite_x002F_Industry_Hidden" 
opt="_Select">
<IMG 
style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; VERTICAL-ALIGN: middle; BORDER-RIGHT-WIDTH: 0px" 
onclick="ShowDropdown('ctl00_m_g_4cfb4dc8_9323_4849_bbfb_95af4cc4f470_ctl00_ctl02_ctl00_ctl01_ctl00_ctl00_ctl03_ctl00_ctl00_ctl04_ctl00_ctl01');" 
alt="Display lookup values" 
src="INFORM%20Documents%20-%20TMB-0000-SA-9898_files/dropdown.gif">

Thus dropdown list 2 is made of text box and image button which should be disabled as well.

This image button can be found by control id of a text box mentioned in onclick event handler which uses this id in ShowDropdown function call. So this button can be found by content of onclick attribute. Since collection of elements in document.all places elements in order of their declaration in document then we do not need to search all this image button in all the elements but instead of this can check the next element after the have just found element.

Disable field javascript version 2:

<SCRIPT language=javascript>
/// <summary>
/// Disables EditForm field for the specified column title
/// </summary>
function DisableField(title)
{
    for(var i = 0; i < document.all.length; i++)
    {
        var el = document.all[i];
        // find html element with specified title
        if(el.title == title)
        {
            el.disabled = true; // disable
 
            // if the next element has a reference to the current element
            // then disable if as well
            if(i < document.all.length - 1)
            {
                var el2 = document.all[i + 1];
                if(el2.outerHTML.indexOf(el.id) > 0)
                {
                    el2.disabled = true;
                }
            }
            break;
 
        }
    }
}
DisableField("Company");
DisableField("Site/Industry");
</SCRIPT>