Wednesday, March 28, 2012

Custom Form for SharePoint List - FieldRenderingControl

I was working on a feature to enable bulk edit of list items..For this purpose, I wanted to develop a custom page in which all the list fields/columns should be rendered for the user to submit his data..

I thought I might have to build the form rendering logic myself..i.e, render a text box for text fields, drop down for choice fields etc..

But to my pleasant surprise, I chanced upon the "FieldRenderingControl" property of SPField, and it turned out that the complete rendering logic could be achieved with just few lines of code, as shown below:

SPList list = web.Lists[new Guid(listID)];
foreach (SPField field in list.Fields)
{
     BaseFieldControl 
renderingControl = field.FieldRenderingControl;
     
renderingControl .ID = field.Id.ToString().Replace("-", "_");
     
renderingControl .ControlMode = SPControlMode.New;
     
renderingControl .ListId = list.ID;
     
renderingControl .FieldName = field.InternalName;
     
renderingControl .RenderContext = SPContext.GetContext(HttpContext.Current, list.DefaultView.ID, list.ID,   web);

      myPanel.Controls.Add(renderingControl); //Add the control dynamically to a panel on page
}

This is it.. The above code will render all the fields in the list with the appropriate edit controls..

Note: You can use the following condition, within the above loop to hide read-only and non-editable fields:

if (field.ShowInNewForm.GetValueOrDefault(true) 
                                && field.Hidden == false 
                                && field.ReadOnlyField == false
                                && field.FieldRenderingControl != null
                                && (field.ShowInEditForm ?? false || field.CanBeDisplayedInEditForm))
{
      // Render the fields
}

Tuesday, March 27, 2012

Auto-closing SharePoint pop-up window after exporting to Excel

Recently I was working on a utility to export SharePoint list view data to a CSV file.. The logic was to open an application page using SharePoint's dialog framework, do the export logic in page-load of that application page and finally close the pop-up..

I thought closing the pop-up after completion would be fairly simple. I thought I can just use

Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");

after process completion. But here was the challenge..To save the CSV data, I had to use the following code:


HttpContext context = HttpContext.Current;
context.Response.Clear();
context.Response.Write(csvData.ToString());
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName + ".csv");
context.Response.Flush();
context.Response.End();



The problem was, after changing the content type of Response to "text/csv", it was not possible to execute any JavaScript from server code to close the pop-up window..

After trying many options, I was about to give up when I found this method definition on MSDN..
SP.UI.ModalDialog.commonModalDialogClose(dialogResult, returnVal);
Closes the most recently opened modal dialog with the specified dialog result and return value.
Now, the solution was simple.. All I had to do was to set a cookie in the server side after process completion, and in the parent page, run a timer job every few seconds in JavaScript to check for the same cookie, and if found, delete the cookie, stop the timer and close the pop-up..

Note: To process the cookie in JavaScript I used this great library, because of which it turned out to be just a single line of code..
http://code.google.com/p/cookies/

Here is the complete code..

Javascript to open and close the pop-up:

function OpenPopUp() {
    var oUrl =  'http://mysite/_layouts/SPExcelExport/SPExcelExport.aspx;
    var options = {
        title: 'Excel Export',
        allowMaximize: false,
        showClose: true,
        width: 300,
        height: 90
    };
    SP.UI.ModalDialog.commonModalDialogOpen(oUrl, options, null, null);//Open pop-up
    var millisecondsToWait = 2000; //Run every 2 seconds to check for cookie
    var intrvl = setInterval(function () {
        if (jaaulde.utils.cookies.get('csvexportcookie') != null) { //check if cookie is found
            jaaulde.utils.cookies.del('csvexportcookie'); //Delete the cookie
            SP.UI.ModalDialog.commonModalDialogClose(1, 1); //Close the pop-up
            clearInterval(intrvl);//Clear timer 
        }
    }, millisecondsToWait);
};

Server side code in the pop-up page:


HttpCookie oCookie = new HttpCookie("csvexportcookie", "completed"); //Set the Cookie
Response.Cookies.Add(oCookie);

HttpContext context = HttpContext.Current; //Write the CSV data to current response
context.Response.Clear();
context.Response.Write(csvData.ToString());
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName + ".csv");
context.Response.Flush();
context.Response.End();

That was it.. Problem solved!