Generate SharePoint form to save items into SharePoint lists dynamically with SharePoint Web Controls


Overview

SharePoint developers are thinking what is the benefit of creating a custom  asp.net forms to add items in lists , it’s something like create a normal aspx page to add an item to database ! where is the powerful of SharePoint here in this case specially if there is a change request later to add a new field to list that will make a load for developers to add a new text box or any another control to the form that will insert a new item !

so let’s play with SharePoint controls and list fields that will give us the power to create  dynamically generated  forms  to add and edit items in SharePointlists , this solution will generate a SharePoint Controls rather than normal asp.net controls.

A problem that our solution can fit into it

Suppose you create some SharePoint survey’s  and your task is to create a custom form for answering each one by users

As we know SharePoint survey is a normal SharePoint list , questions are representing as a list columns and answers are representing as  list items , each item contain a “created by” column that contain the username who answer this survey

The traditional way for example create a survey with 5 questions then create a form that contain 5 asp.net controls to add answers, for sure you will map questions types with your controls for example if the question type is a multiple so you will add  checkboxes to your form and you will add a choices number like these which you entered in the question type , this way as you build a normal asp.net form to add an item to a database table !

Or create a data form web part from SharePoint designer , the problem is you will create this web part for each survey and starting enhance the style for it and everything every time you will create a new survey !

But our way is using SharePoint fields and web controls rendering ways to render the controls on form dynamically and it will auto reflect any new question (lits column ) added to the survey and render it as a SharePoint control (not normal asp.net control !) in your form  , you don’t need to add more code for the new added column and also you can use this way with any list just write your code once then change the name of the list , your code will generate a form to add a new item dynamically with saving item code also !

So we will create our example based on this case (survey answering form)

Understanding SharePoint Web Controls , SharePoint List fields objects

1-SPField class represents a list column and it contains and attribute named “FieldRenderingControl” we will use this attribute to return the sharepoint web control for example if we have a column with type single line of text the attribute “FieldRenderingControl” will return TextField object that represent as a SharePoint text field and the same way for all types , here you can find the famous SharePoint web controls that we can return from SPField.FieldRenderingControl

Control
TextField
CheckBoxChoiceField
NumberField
RadioButtonChoiceField
RichTextField
BooleanField
DropDownChoiceField
DateTimeField

2-all sharepoint web controls inherits from BaseFieldControl  that means SPField. FieldRenderingControl

3-each web control must specify some attrbuites to render (except DateTimeField)

Attrbuite Description
ID Id for this control
FieldName The field name that this control will lookup from or to it
ControlMode The mode that will control presenting  , we have three modes (New , Edit , Display)
ItemId Id for the item from column ID
ListId Guid for this list

4-we will loop through an SPList.Fields to get all fields for this list then we will filter then to get our custom fields only , we can use SPField.Reordable attrbuite to specify  the fields which we want to represent as a web controls , for sure you will recive Created By field and if you want to hide it just check through the loop if this field is Created By escape it from rendering

Part 1 Build your form dynamically

-I will describe each part of the code with a  line comment above each part

//our list

_listObj = web.GetList(string.Format(“/Lists/{0}/allitems.aspx”, “Sports Survey”));

/*create a table to add our form controls on it*/

Table table = new Table();

TableRow row = new TableRow();

TableCell cell = new TableCell();

cell.Text = string.Format(“<h3>{0}</h3>”, _listObj.Title);

cell.ColumnSpan = 2;

row.Cells.Add(cell);

table.Rows.Add(row);

foreach (SPField field in _listObj.Fields)

{

if (field.Reorderable)

{

//add a title for each control

row = new TableRow();

cell = new TableCell();

cell.Text = string.Format(“<strong>{0}</strong>”,field.Title );

row.Cells.Add(cell);

table.Rows.Add(row);

//create your sharepoint control from its field

BaseFieldControl webControl =          field.FieldRenderingControl;

//create an id for this control that we will get the value of this control with this id later

webControl.ID = string.Format(“ctrl_{0}”,field.InternalName);

webControl.FieldName = field.Title;

webControl.ItemContext =SPContext.GetContext(HttpContext.Current, _listObj.DefaultView.ID, _listObj.ID, _listObj.ParentWeb);

webControl.RenderContext = SPContext.GetContext(HttpContext.Current, _listObj.DefaultView.ID, _listObj.ID, _listObj.ParentWeb);

webControl.ControlMode = SPControlMode.New;

webControl.ListId = listObj.ID;

//check for the field is not created by field

if (!field.InternalName.ToLower().Equals(“author”))

{

row = new TableRow();

cell = new TableCell();                                                cell.Controls.Add(webControl);

row.Cells.Add(cell);

table.Rows.Add(row);

}

}

}

//add your table to a lable inside your user control or web part

lblContainer.Controls.Add(table);

so we will see our form now , if you change your form name it will render its controls auttmtically , if you will add or delete any field it will reflect here without any code changing like this

Very nice result !

Part 2 add your save button and save code to save your item

1- first thing create a method that get the value from form controls like this

public string getControlValue(Control SPCtrl)

{

if (SPCtrl is TextField)

{

return ((TextField)SPCtrl).Text;

}

if (SPCtrl is CheckBoxChoiceField)

{

return ((CheckBoxChoiceField)SPCtrl).Value.ToString();

}

if (SPCtrl is NumberField)

{

return ((NumberField)SPCtrl).Text;

}

if (SPCtrl is RadioButtonChoiceField)

{

return ((RadioButtonChoiceField)SPCtrl).Value.ToString();

}

if (SPCtrl is RichTextField)

{

return ((RichTextField)SPCtrl).Text;

}

if (SPCtrl is BooleanField)

{

return ((BooleanField)SPCtrl).Value.ToString();

}

if (SPCtrl is DropDownChoiceField)

{

return ((DropDownChoiceField)SPCtrl).Value.ToString();

}

if (SPCtrl is DateTimeField)

{

if (((DateTimeField)SPCtrl).Value == null)

return “NullDateTime”;

else

return ((DateTimeField)SPCtrl).Value.ToString();

}

return “”;

}

This method will check the type of your SharePoint control then return its value , sure you can add more just I add here some famous controls

2-second inside your event handler of save button  we will make a loop again through our list fields (like the one we did when we rendering    ) then just we will find the control inside the label container control with name “ctrl_”+field.InternalName as we named all our controls in rendering with this schema

_listObj = web.GetList(string.Format(“/Lists/{0}/allitems.aspx”, “Sports Survey”));

foreach (SPField field in _listObj.Fields)

{

if (field.Reorderable)

{

Control ctrl = lblContainer.FindControl(string.Format(“ctrl_{0}”, field.InternalName));

//pass the control to our method that will get the value

string  ctrlValue =getControlValue(ctrl);

//create a new list item to added to the list

SPListItem listItem =_listObj.Items.Add();

//check the value if not “NullDateTime” firstly then save the item , I did this solution because if the datatime field with null value and we want to add this field with null value it will occur and error so we will check for this value then escape if it is true

if (ctrlValue != “NullDateTime”)

{

// update each listitem with its value we got the name of the field dynamiclly as we see

listItem[field.InternalName] = ctrlValue;

}

}

//after finish looping for all fields and fill all columns in listitem object with the values returned from the form controls we will update not this

listItem.Update();

you will find your item added dynamically , you can use this code for any type of lists or document libraries just change your name of the list when you create your SPList object

Tips

-You can make this code as a generic user control that take some  paramteres like the name of the list , item id (if you want to view your control in edit mode or display mode for a specific item) , Control Mode (SPControlMode enumeration)

- You can change the layout and style of your form and controls as you want , you can escape the part of using a Table class that I described It here and replace it with your own way like creating MVC asp.net page and render with another way to help web site desinger to apply styles and so on without need to open your code.

Hope it will help

About these ads

34 thoughts on “Generate SharePoint form to save items into SharePoint lists dynamically with SharePoint Web Controls

  1. Hi,

    When spfield type is TaxonomyFieldType and BaseFieldControl ControlMode is set to SPControlMode.Edit i am getting error like this:

    Failed to get value of the “metalib” column from the “Managed Metadata” field type control. See details in log. Exception message: Invalid field name.

    In SPControlMode.Display mode it works good.

    Maybe someone have advices?

  2. I am just curious. What if there is any validation to each field? How can I find out? Example some validation formula, default value or max length for text input.. Is there anyway we can handle from sharepoint list model?

    • Validations here are related to columns itself , for example if you configure the column to be required so the text field for it will be required ,etc…

      if you are talking about advanced validation like regular expressions and other validations the only way to implement thorough the code of rendering

  3. Thanks, it helped me a lot. By the way, you can get value of any field using reflection:
    public object getControlValue(Control SPCtrl)
    {
    var type = SPCtrl.GetType();
    PropertyInfo pinfo = type.GetProperty(“Value”);
    object value = pinfo.GetValue(SPCtrl, null);
    return value;
    }

    and set field to your list item as ordinary:

    item[fieldID] = value;

  4. Hi

    I am trying to update the list item using the custom functionality. When i click on the button i am getting the error

    “Failed to get value of the “mycloumnnamehere″ column from the “Single line of text” field type control. See details in log. Exception message: Object reference not set to an instance of an object”

    I am loosing the controls in the label when postback is occured..(.like when i clcik on button.)

    Any solution for this issue…?

  5. Failed to get value of the “test2″ column from the “Single line of text” field type control. See details in log. Exception message: Object reference not set to an instance of an object..

    I too get this error has any one found solution for this.. one..

  6. Wael what is the architechture of your app.. Is it custom user control or some kind of webpart..

    I am creating ascx file and rendering in to sharepoint as child

    userControl1 = (UserControl)Page.LoadControl(@”/_controltemplates/Trials/controlname.ascx”);
    this.Controls.Add(userControl1);

    But I run in to problem. where I running to problem finding values when trying to save the data.. becasue some how lable is empty by the time posting back .. to save. data..

    • in the getControlValue() method add this condition that check if the type of control is user\group field web control

      if (SPCtrl is UserField )

      {
      SPFieldUserValue userValue=(SPFieldUserValue)SPCtrl.GetFieldValue(listitem[SPCtrl.Title].ToString());

      return ((UserField)SPCtrl).Value;

      }

      value will return a string like that “145;#BobR;#11;#Sally” for example 145 is the user ID and BobR is the username and for multiple values it will be like the above schema

  7. Moss_SharePoint :

    Wael Mohamed :
    Just check this is the first time for load this page using
    if ( ! Page.IsPostBack)
    {
    // your form generation code here
    }
    and it will work fine

    If I do that it doesn’t render any controls as we are adding these controls dynamically.

    It works if I remove ItemContext & RenderContext statements. Whta about the validators? Any suggestions?

  8. Wael Mohamed :

    Just check this is the first time for load this page using
    if ( ! Page.IsPostBack)
    {
    // your form generation code here
    }
    and it will work fine

    If I do that it doesn’t render any controls as we are adding these controls dynamically.

    • Hi Wael,
      I am also getting the same object reference error on the title field. I am adding the controls in page load event in application page. If I do it inside a !Page.Ispostback condition then I cant get those controls when I do a FindControl in the Save button click event. So could you please tell how to solve this problem ?

  9. I get below error when I click on Submit button.

    “Failed to get value of the “Question1:” column from the “Choice” field type control. See details in log. Exception message: Object reference not set to an instance of an object..”

    The page post back and throws this error.

    Also, how to validate these controls?

    • Forgot to mention…I have my code there in page load event and it loads without any error for the first time. But when i click on the button, it thorws the error mentioned.

    • Abhilash Joseph :

      Hi Wael,
      I am also getting the same object reference error on the title field. I am adding the controls in page load event in application page. If I do it inside a !Page.Ispostback condition then I cant get those controls when I do a FindControl in the Save button click event. So could you please tell how to solve this problem ?

      please copy and past all your code parts

  10. Hi Wael,
    Where to place the code in “Part 1 Build your form dynamically” in the code behind file? Because I have placed them in Page_Init and still they are not able to find in the button click event… Always the lblContainer.FindControl(“control name”) gives null….

    please let me know where could be the issue or where to place that part 1 code…..

    • And when I place the code in the CreateChildControls() or Page_Init() here is the exception coming always.

      Failed to get value of the “Column name” column from the “Lookup” field type control. See details in log. Exception message: Object reference not set to an instance of an object..

      Troubleshoot issues with Microsoft SharePoint Foundation.

      Correlation ID: 168222b8-1728-43f1-aea9-156e4eaf1424

      Date and Time: 6/30/2011 8:14:17 AM

      Please let me know what might be the issue…..

  11. Thank you for This is a great article wael.

    still this method has an issue with people / group field!

    it doesn’t validate the typed values in the field when press enter or click on the perosn icon near the field, did you try it ?

    i think the reason it doesn’t runs the javascript or thomething like this !!!!

    any clue ????
    thanks in advance

    • I think so , maybe you can solve this problem by opening the master page file ( the main one ) for the SharePoint portal then copy scripts tags in the head to your custom master , or you can try to find this scripts tag registered in editform page for lists you can fins this page inside Layouts folder

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s