Showing posts with label DataView Web Part. Show all posts
Showing posts with label DataView Web Part. Show all posts

Monday, July 28, 2008

Customized Input Forms: The JavaScript Approach

Correction [02.13.2009]: I have recently been informed of an issue with field values not saving when they are disabled for the user. Please see my post here for updated code.

If any of you have had to customize the input forms for lists or libraries in SharePoint, you'll know that it is not easy. You can customize the form with a custom list form web part, but you better not delete the original list form web part, otherwise your list gets hosed. You can have both on the page (with the original web part hidden), but then you lose attachment support with JavaScript errors. If you create a new page without the original list form web part, then you get a nice JavaScript alert saying that the form has been customized to not allow attachments. If you used the custom list form web part, then you might find it cumbersome and tedious to make changes when new columns are added. I have tried countless recommendations for modifying the list input form, and none of them really seemed to work cleanly and effectively. Until I stumbled across the forum discussion located here on MSDN Forums.

Of all of the ideas proposed in this forum topic, I found tscheifler's usage of JavaScript quite intriguing. There were some limitations that I found when implementing their exact solution (most notably around disabling columns of type: Lookup, Date and Time, and Multiple lines of Text). Extending this, and incorporating various other bits of information lying about the web, I ended up with a solution I am quite happy with. This assumes you have an existing list with several fields you would like to hide/disable for certain user groups. We will begin by modifying the "NewForm.aspx" page, but these steps will work for any of the input forms:
  1. Open the "New Form" for the list and remove all query string variables (should end up with http://server/site/listname/NewForm.aspx)
  2. Append "?ToolPaneView=2" onto the end of the url (http://server/site/listname/NewForm.aspx?ToolPaneView=2)

    Note: this places the page into "Add a Web Part" view
  3. Add a new "Content Editor Web Part"(CEWP) to the page after the existing web part
  4. Modify the source view of the CEWP to include this code:
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    function disableChildren(currentElement)
    {
    if (currentElement)
    {
    if(currentElement.tagName == "IFRAME")
    {
    frm = window.frames[currentElement.id].document;
    disableChildren(frm.getElementsByTagName("html")[0]);
    }
    var i=0;
    var currentElementChild=currentElement.childNodes[i];
    while (currentElementChild)
    {
    disableChildren(currentElementChild);
    i++;
    currentElementChild=currentElement.childNodes[i];
    }
    if (currentElement.tagName)
    {
    currentElement.setAttribute("disabled", "true");
    currentElement.setAttribute("contentEditable",
    "false");
    currentElement.setAttribute("onclick", "");
    currentElement.removeAttribute("href");
    }
    }
    }
    
    function hideRowsAfter(currentRow)
    {
    row = currentRow.nextSibling
    while (row)
    {
    row.style.display = "none";
    row = row.nextSibling;
    }
    }
    
    function findControl(FieldName, opp)
    {
    FieldName = "FieldName=\"" + FieldName + "\"";
    //get all comments
    var arr = document.getElementsByTagName("!");
    for (var i=0;i < arr.length; i++ ) 
    {
    // now match the field name
    if (arr[i].innerHTML.indexOf(FieldName) >= 0)
    {
    switch(opp) 
    {
    case 0:  //disable all children
    disableChildren(arr[i].parentNode.parentNode);
    break;
    case 1:  //hide row
    arr[i].parentNode.parentNode.style.display="none";
    break;
    case 2:  //hide all rows after current
    hideRowsAfter(arr[i].parentNode.parentNode);
    break;
    default:
    break;
    }
    }
    }
    }
    
    function disableControls(inputArray)
    {
    for (var i=0; i < inputArray.length; i++)
    {
    findControl(inputArray[i], 0);
    }
    }
    
    function hideControls(inputArray)
    {
    for (var i=0; i < inputArray.length; i++)
    {
    findControl(inputArray[i], 1);
    }
    }
    
    function hideControlsAfter(input)
    {
    findControl(input, 2);
    }
    
    //Usage:
    // disableControls(["Field Name 1", "Field Name 2"..]);
    // hideControls(["Field Name 1", "Field Name 2"..]);
    // hideControlsAfter("Field Name");
    
    //-->
    </SCRIPT>
  5. Follow the "Usage notes" to add calls to the disableControls, hideControls, or hideControlsAfter functions which will modify the fields displayed on the page

    Note: you can find the values to put in place of "Field Name 1" and "Field Name 2" by viewing the source view for the page and searching for: FieldName="
    The value within the double quotation marks will be what you enter inside the arrays in the hide/disable function calls.
  6. In the CEWP's tool pane, add security groups or audiences which should have the fields hidden/disabled to the "Target Audience" setting
  7. Save the web part properties, and click the "Exit Edit Mode" link in the upper right below "Site Actions".
Now you should see all of the fields hidden or disabled based on your security settings specified within the CEWP.

To extend this into a more reusable solution, I created a custom CEWP with this JavaScript code, exported it to a .dwp file, and then uploaded it to the Web Part gallery. Then, the only modifications needed are to add this web part to the page (under ToolPaneView=2 view), add the "usage" functions, and add the security groups to the targeted audiences.

This solution now hides/disables fields specified within the original list input form, which retains the attachment functionality, while being able to easily make modifications when new fields are added/modified based on column ordering.

However, there are some limitations to this method. None of which were show stoppers for me, since this method is very easy to undo (simply remove the CEWP from the forms). Especially in the interim until Microsoft is able to fix this little problem and offer a clean, efficient, and effective method of customizing input forms. These limitations are:
  • Security groups or audiences need to be created for the group of users which should have limited access to list fields, which excludes the users with access to the restricted fields.
  • You cannot make any of the hidden/disabled fields required unless you specify default values, as the fields will still remain on the page and submit data, they are just hidden to the user
  • If the user employs firebug or other plugins which can alter JavaScript, they could unhide/undisable the fields you removed and then manipulate the data
  • Information in these fields is still visible to users if the columns are displayed within list views, as well as Source View of the input form

Enjoy!
--andrew

Wednesday, April 2, 2008

DataView Web Parts and Page Layouts

The DataView Web Part is a nice tool to customize the way information is presented on a page. Unfortunately, this web part is not available through the browser's "Add Web Part" interface, and must be added through SharePoint Designer. The problem I ran into was that pages attached to a page layout cannot be directly modified within SharePoint Designer.

I decided to detach the page from its layout and add the DataView Web Part. Everything seemed to work, except I started to receive errors stating "This Web Part Page has been modified since you opened it." I figured this was related to detaching from the Page Layout (I may have hosed something up unknowingly). I then reattached the page to its layout and everything ended up working fine.

Therefore, if you need to add a DataView Web Part to a page attached to a layout, I suggest doing the following(all done within SharePoint Designer):
  1. Detach the Page from the Page Layout
  2. Go through the necessary steps to add a DataView Web Part to an existing zone on the page
  3. Reattach the Page to it's Page Layout
This was fantastic since detaching/reattaching to layouts does not change any web parts or customizations made to those web parts. Also, once the DataView Web Part is on a page, you can simply modify it's display through the browser using the XSL editor.

Note: I have not attempted to reattach a page to a layout after new zones have been added and do not know exactly what will happen.

Enjoy!
--andrew