Pages

Monday, June 22, 2009

How to access fields of List Item in ItemAdding and ItemUpdating event handlers into SharePoint

When we need to validate something or put restriction before adding or modifying data, at that time we need to use ItemAdding or ItemUpdating Event Handler, here I’ll demonstrate how to access fields of List into event handlers.

Example:

As per my requirements, I don’t want to add duplicate Name into List. For this I need to check that condition before I add and update item to List, I need to use “ItemAdding” and “ItemUpdating” event handlers

public override void ItemAdding(SPItemEventProperties properties)
{
string strName = string.Empty;

foreach (DictionaryEntry entry in properties.AfterProperties)
{
if (entry.Key.Equals("Name"))
{
strName = entry.Value.ToString();
}
}

SPList list = properties.OpenWeb().Lists[properties.ListId];
SPQuery query = new SPQuery();
query.Query = "<Where><Eq><FieldRef Name='" + list.Fields["Name"].InternalName + "' /><Value Type='Text'>" + strName + "</Value></Eq></Where>";
if (list.GetItems(query).Count > 0)
{
properties.Cancel = true;
properties.ErrorMessage ="Name already exists!";
}
}
public override void ItemUpdating(SPItemEventProperties properties)
{
string strName = string.Empty;
foreach (DictionaryEntry entry in properties.AfterProperties)
{
if (entry.Key.Equals("Name"))
{
strName = entry.Value.ToString();
}
}
SPList list = properties.OpenWeb().Lists[properties.ListId];
SPQuery query = new SPQuery();
query.Query=  "<Where><And><Neq><FieldRef Name='"+ list.Fields["ID"].InternalName+ "' /><Value Type='Number'>"+ properties.ListItemId+  "</Value></Neq><Eq><FieldRef Name='"+ list.Fields["Name"].InternalName+ "' /><Value Type='Text'>"+ strName+ "</Value></Eq></And></Where>" ;
if (list.GetItems(query).Count > 0)
{
properties.Cancel=true;
properties.ErrorMessage ="Name already exists!";
}
}

33 comments:

  1. Hi,
    Great post. I have tried it but don't seem to get it working. I implemented the ItemAdding event handler but instead of sharepoint displaying the error nicely I get a server error page, although the error message I wanted to display appears. Is there another place I should modify? Or am I missing something? Any help would be nice.
    Thank you.

    ReplyDelete
  2. Hi,
    Solved the problem. It had something to do with my web.config . The changes I made:

    ...
    ...


    ...
    Thanks.

    ReplyDelete
  3. Alexandra

    Thanks for comment and also giving feedback. What changes you did to web.config to solve your problem? I think you made changes for CallStack and CustomErrors. If possible please share details.

    Thanks and Regards

    ReplyDelete
  4. Hi Disha,

    This is exactly what I'm looking for! However, I have a quick question. In your foreach loop, why did you use the type DictionaryEntry? Where did this value come from, and how should I change it?

    Thanks for the post

    ReplyDelete
  5. Hi

    Thanks for appreciation and comments. Now when you save a particular ListItem, all field values that we entered of that listitem store as type DictionaryEntry (System.Collections).

    I think, you can also try below lines of code and may be it solves your problem.

    public override void ItemAdding(SPItemEventProperties properties)
    {
    string Name = "";
    using (SPWeb web = properties.OpenWeb())
    {
    Name = web.Lists[properties.ListId].Fields["Name"].InternalName;

    }
    properties.AfterProperties[Name] = "ChangedValue";
    }

    Enjoy !!!!!!!

    ReplyDelete
  6. Hi Disha,
    I wrote similar code to validate the data while user is entering in the columns of a list but writing code in event handlers with properties.errormessage= some text will display a new page with go back to the site option where user has to go back and reenter the data from scratch, instead we can use jscript so that the error message will be shown in a pop-up window and data in other columns remains unaltered and after pressing ok they can edit the column with correct data.I am thinking so but I have no idea how to do that.Can you give me some idea?

    ReplyDelete
  7. Hi Disha,
    I am sorry to include this comment here but I want your suggestion. I have 2 lists namely 'Tasks' list and 'stages' list.Tasks list will have an 'TID'(task id)'Create a Stage?' and 'link to the Stage list' columns along with some other columns, so when creating a item(new task) in tasks list if they say 'yes' for 'Create a stage?' column they will see a link to that corresponding stage list in the 'link to stage list' column and this data will get copied in to that Stages list automatically all this i did using event handlers.So the stages list will consist of all the stages for all the tasks in the tasks list with unique task ID's and Stage ID's.Now where I got struck is I have to show them only stages of a that particular task in the Stages list if already existing or I have to copy this data and make them create new stage when they click on 'link to stage list' in tasks list, it means filtering has to be done automatically in the stages list with respect to the TID value in the Tasks list.Except filtering part I wrote all other code for item added/updated and deleted cases.Do you have any idea or webpart apart from writing custom filter code?
    Any suggestion is appreciated.

    ReplyDelete
  8. Harish,

    I like your requirement and it’s very interesting. Good work!

    Now if you are looking for any Filter web part, then I think you can use and play with out of the box Filters web part, "SharePoint List Filter” web part is one of the out of the box web part, in this web part you need to select List Name, select filter column names and then you can send output or results to any another web part into page …

    So please see whether you can leverage and use "SharePoint List Filter” web part or any other out of the box Filters web part or not. I think custom coded filter web part is last option if you didn’t find anything from out of the box.

    Good Luck!!

    Disha Shah :)

    ReplyDelete
  9. Harish,

    Logically there must be some way in which we can write JavaScript into event handler functions, but I think properties.ErrorMessage behavior is out of the box, though I have found below links, may be you can find something helpful for you.

    1 . Very good link :

    http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/22d79c27-e5ef-4b29-b845-b54976940f3a/
    2. Link talks about that you can’t use JavaScript into event handlers.
    http://phani-madhav.blogspot.com/2008/03/custom-script-while-submiting-list-item.html
    3. http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/945591e2-da92-4b60-881f-b9da89999634

    4. http://www.sharepointkings.com/2008/06/redirection-from-event-handler.html : check about SPUtility.redirect method and may be you can redirect control to same page instead of writing properties.ErrorMessage values.

    Enjoy,
    Disha Shah :)

    ReplyDelete
  10. Thanks for your suggestion Disha. I will look in to Sharepoint list filter webpart and let you know what solution I choose finally.

    ReplyDelete
  11. Hi Disha,
    I have tried using list filter webpart and query string url filter webpart but I didnt get the solution may be I didnot make a wright approach using these filters but I just modified my list view filter like filter when column ID is equal to[ID] and in my event handlers in the column where I hardcoded the link to another list I did smthng like after http://....TIDView.aspx? + "?ID=" + newitem["ID"]); . In fact this is the basic idea of a query string filter.
    Thus I got the soulution.

    ReplyDelete
  12. Hi,
    This is Harish again.I got an issue with event handlers I have a list in a publishing site on which I wrote 2 event receivers and each of which furthur includes 3 types of event handlers(item added/deleting/updating same in both the cases). Here the problem is in item updating case I am getting Save conflict error I thing every developer using updating event handlers might have seen this . I am even using disable and enable event firings but still unable to get rid of that error. I am using updating event because while item updating for a column 'Status' I need to check what its value is before.properties and after.properties(open/cloesd). Can you help me?

    ReplyDelete
  13. Hey Harish

    That's really good that you got your solution by filter web part. Great Job!!

    Disha Shah :)

    ReplyDelete
  14. Hi Harish,

    Yeah I also got same type of problem while working with event handlers, below are the steps which I followed to resolve my issue, you can also try to do same thing and see whether it�s will solve your problem or not.

    For every update to a list item the SPList.update() method needs to be called to save the changes back to database. The pattern which I like to follow is to retrieve the SPWeb GUID from the current site, then call a separate instance of SPWeb object per individual list update. I know that this is a tedious pattern and doesn't necessarily have to be used on all occasions, but may be it will save you from this annoying little exception.

    Sample Code:

    protected void itemUpdate(string FieldName, string FieldValue, SPSite site, Guid webID, Guid listID, Guid itemID)
    {
    try
    {
    using (SPWeb web = site.OpenWeb(webID))
    {
    web.AllowUnsafeUpdates = true;
    SPList list = web.Lists[listID];
    SPListItem item = list.Items[itemID];
    item[FieldName] = FieldValue;
    item.Update();
    list.Update();
    web.AllowUnsafeUpdates = false;
    }
    }
    catch(Exception ex)
    {
    Response.Write("An error occured while updating the items");
    }
    }

    When disposing of SPWeb object, remember CONTEXT things also. If you retrieve SPWeb object from the current context (SPContext.Current.Web), you cannot and should not dispose of SPWeb object.

    If you dispose of the Web which is being used by the current context, it's the equivalent of ripping the ground from under your feet!!

    If you are doing multiple list updates the best approach would be to open and dispose of a separate instance of SPWeb object.

    Disha Shah :)

    ReplyDelete
  15. Thanks for the Code Disha,
    I have already tried this code but this didnot work but finally I solved the problem by replacing properties.listitem.update() with properties.listitem.SystemUpdate(false)in item updating event handler.

    Regards,
    Harish

    ReplyDelete
  16. Hi Harish,

    It’s good to know that you got the solution.

    Thanks for sharing the information.

    -Disha Shah

    ReplyDelete
  17. Hi Disha

    I need to create alert through sharepoint object modal for logged in users. If logged in user subscibe alert in my custom webpart for any docuemnt libraray item, than when ever that subscribed item will modify, user will get alert with that document url. i have a webpart which shows the selected documents from document library. Over there i need to give this fcility.

    Thanks in advance.

    Regards
    Sai

    ReplyDelete
  18. Hi Sai

    I think you can fulfill your requirement by Alerts Facility from SharePoint Interface only, there is no need to go for SharePoint Object Model.

    Please let me know why you want to use SharePoint object model?

    Best Regards
    Disha Shah

    ReplyDelete
  19. Thanks for sharing ur knowledge to others..

    ReplyDelete
  20. Hi,
    Great work. I am trying to used it in my sharepoint site but the entry.Key doesn't seem to show the internal name. I have a content type that I have created programatically with columns that I gave internal names, but they don't seem to show in entry.Key. Can you please help me?

    Thanks.

    Have a great day,
    Anisia

    ReplyDelete
  21. Hi Anisia


    Entry.key may return the display name of the field. So you can get internal name by using this code

    SPList list = properties.OpenWeb().Lists[properties.ListId];


    foreach (DictionaryEntry entry in properties.AfterProperties)
    {

    Strint strIntername = list.Fields[entry.Key].Intername;

    }

    Hope this helps!!!Please let me know and describe in detail if I am unable to understand your problem correctly.

    Thanks & Regards
    Disha Shah

    ReplyDelete
  22. Thanx but i want to access item field insade property such as Due Time and Assigned to
    how can i do that ??

    ReplyDelete
  23. Hi Tarhoni,

    "Due Time" and "Assigned To" these two are Fields for the current List Item? If yes, then you can add like these

    string strDueDate = string.Empty;
    string strAssignedto = string.Empty;

    foreach (DictionaryEntry entry in properties.AfterProperties)
    {
    if (entry.Key.Equals(“DueDate”)) \\internal name of duedate
    {
    strDueDate = entry.Value.ToString();
    }
    else if (entry.Key.Equals(“AssignedTo”)) \\internal name of AssignedTo
    {
    strAssignedto = entry.Value.ToString();
    }

    }

    Hope this helps!!!

    Thanks & Regards
    Disha Shah

    ReplyDelete
  24. Hi Disha,

    Nice blog.
    Disha, i m getting problem in ItemAdded event where i m not able to display error message.

    Properties.Errormessage = "error";
    properties.cancel = true;

    Thanks & Rgds,
    Hardik Shah

    ReplyDelete
  25. Hi Hardik

    Thanks for the appreciation!!!

    One question raised in my mind for your question,

    If it does not display that error message it means there is some problem before that line.If possible, Can you please post that code before that line so it makes easier for me to solve your problem?

    Thanks & Regards
    Disha Shah

    ReplyDelete
  26. Hi Disha,

    Thanks you so much.
    since Last 2 days i have been trying to get item value in the variable in itemadding event. but each time it gives error null ref.
    But using dictionaryEntry i can able to get the values.... :)

    Regarding my earlier post:
    ItemAdded problem:
    I have written spquery and its give me the record. till that everything is good.

    now;
    SPListItemColletion TimeList = CRBlist.GetItems (TimeQuery);

    if(TimeList.Count > 1)
    {
    Properties.ErrorMessage = "Error massage";
    Properties.Status = SPEventReceiverStatus.CancelWithError;
    Properties.Cancel = true;
    }
    }
    }

    This code in not in any try or catch block. This code is in ItemAdded event.

    ReplyDelete
  27. Hardik

    Just change the order of the statement that you have written for eventhandler.

    //Properties.Status = SPEventReceiverStatus.CancelWithError; --Do not write this one and try
    properties.Cancel = true;
    properties.ErrorMessage = "Deleting is not supported.";

    Hope this helps!!!
    Disha Shah

    ReplyDelete
  28. Hi Disha,

    I have question regarding 'ItemAdding' event handler, I have attached my 'ItemAdding' event to my document library and I need to take some meta data associated with uploading document and compare with values, but I am not getting List Item ID and not getting any key/values by accessing after properties object.


    Do you know any way to get Meta data associated with documents in 'ItemAdding' event handler?

    Thanks for looking into above question :)

    ~Sanket

    ReplyDelete
  29. Hi Disha,

    I want to encrypt the document before it is added to SharePoint DB. This should handle all the events which can result into document being added into SharePoint such as Add, Check In etc. So can you please help me to achieve above.I have tried the ItemAdding, ItemCheckIngIn events but its giving “Your changes conflict with those made concurrently by another user. If you want your changes to be applied, click Back in your Web browser, refresh the page, and resubmit your changes” error.

    Also is there any way I can get the events for View/Edit document link so on that I can decrypt the document.

    Regards,
    Dharmesh

    ReplyDelete
  30. Hi Dharmesh

    This error occurs case when you save that item same time some other event is also trying to update that item.

    Is there any workflow attached to document library? You can use either "check-in" or add document event handler not use both at the same time on document library.

    If workflow attached use this one to avoid the error.
    web.AllowUnsafeUpdates = true;
    ListItem.SystemUpdate(false);
    or
    ListItem.Update();
    web.AllowUnsafeUpdates = false

    If any question please let me know.

    Are you using Sharepoint 2007 or Sharepoint 2010?

    Disha Shah

    ReplyDelete
  31. Hi Disha,

    I love your work. I have the same requirements as above and using Sharepoint 2007. Where exactly do you put this sample code?

    ReplyDelete
    Replies
    1. Hi

      Thanks for appreciating my work!!!

      I have used this code inside Eventhandler in VS 2008.

      If you need more information, let me know.

      Thanks
      Disha Shah

      Delete
  32. Was in grave despair and on the verge of acute trichotillomania... then I muttered another desperate prayer, and was halfheartedly looking at google results when I stumbled on this. it looked a bit different then I gave it a try, I nearly jumped out of my chair when I saw the ever elusive afterproperties in ItemUpdating show their presence in my test loop.

    Disha - I'm loyal

    ReplyDelete