SPServices Stories #20 – Modify User Profile Properties on SharePoint Online 2013 using SPServices
- SPServices Stories #1 – How to Start a Workflow on Multiple Items in a List
- SPServices Stories #2 – Charting List Data with HighCharts
- SPServices Stories #3 – AddWebPart Method of the WebPartPages Web Service
- SPServices Stories #4 – Using SPServices to Process Files from a Non-Microsoft Source
- SPServices Stories #5 – Gritter and Sharepoint: Integrate Nifty Notifications in Your Intranet!
- SPServices Stories #6 – Custom Quizzing System
- SPServices Stories #7 – Example Uses of SPServices, JavaScript and SharePoint
- SPServices Stories #8 – CEWP, Nintex, jQuery, SPServices and the Client API
- SPServices Stories #9: Developing with Client-side Technologies: jQuery, REST, SPServices and jsRender
- SPServices Stories #10 – jqGrid Implementation Using SPServices in SharePoint
- SPServices Stories #11 – Using SPServices and jQuery to Perform a Redirect from a SharePoint List NewForm to EditForm
- SPServices Stories #12 – SharePoint and jQuery SPServices in Education: A Case Study
- SPServices Stories #13: Durandal SP3: Developing SharePoint SPAs Made Easy
- SPServices Stories #14: Create a Slide Show in SharePoint 2010 using an Announcements List and SPServices
- SPServices Stories #15: Custom Client-side Calendar Query for Office 365 SharePoint Site Using SPServices jQuery Library
- SPServices Stories #17: Multiple Form Fields Autocomplete for SharePoint 2010/2013 using JavaScript
- SPServices Stories #18 – Retrieve Managed Metadata Using JavaScript and SPServices
- SPServices Stories #19 – Folders in SharePoint are as necessary as evil. Make the best of it using jQuery and SPServices.
- SPServices Stories #20 – Modify User Profile Properties on SharePoint Online 2013 using SPServices
- SPServices Stories #22 : SPServices SharePoint Attachments in Internet Explorer 9
- SPServices Stories #21 – Redirect If User Clicked a Button Previously
Introduction
Sometimes people ask me why I’m still bothering with the crufty old SOAP Web Services in SPServices. After all, there are REST and CSOM to play with and Microsoft has decided to deprecate the SOAP Web Services.
Well in some cases, the Shiny New Toys don’t let you get the job done. In cases where you’re implementing on Office365 and simply can’t deploy server side code, SPServices can sometimes be just the right tool. It’s easy to use and it gets stuff done that you need. What more can I say?
I found this nice story from Gary Arora about updating User Profile data a few weeks back. In it, Gary shows us how to easily make those updates on Office365 using SPServices. Gary calls himself “your friendly neighborhood SharePointMan” and he is happy to be have his story be one of my stories.
The Use Case
SharePoint 2013 users need to modify (specific) user-profile-properties client-side without having to navigate away to their ‘MySite’ site and swift through rows of user properties.
(Following is an mock-up showing a simple interface to update a user profile property via CEWP)
The Usual Solution
In the SharePoint 2013 universe there are 2 ways to read/write data client-side. CSOM and REST. Unfortunately CSOM and REST are not fully there yet when it comes to matching the server side functionality.
In this specific case, one could use CSOM or REST to retrieve (read) User Profile Properties but there is no way to modify (update) these properties from client-side. Here’s Microsoft’s official position.
Not all functionality that you find in the Microsoft.Office.Server.UserProfiles assembly is available from client APIs. For example, you have to use the server object model to create or change user profiles because they’re read-only from client APIs (except the user profile picture)
Hence The Dirty Workaround
So our workaround is SOAP, the forgotten granddaddy of Web services. The User Profile Service web service, from the SharePoint 2007 days, has a method called ModifyUserPropertyByAccountName which functions exactly as it sounds. But since SOAP can be a bit intimidating & ugly to write, we’ll use SPServices, “a jQuery library which abstracts SharePoint’s Web Services and makes them easier to use”
So here’s how we’ll use SPServices to modify User Profile Properties. The method is applicable to SharePoint 2013 & 2010 (online & on-prem) versions.
1. Reference SPServices library
You have two options here. You can either download the SPService library and reference it locally or reference it from its CDN:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2013.01/jquery.SPServices-2013.01.min.js"></script>
2. Create updateUserProfile() Function
The following function simulates the ModifyUserPropertyByAccountName method on the User Profile Service web service.
function updateUserProfile(userId, propertyName, propertyValue) { var propertyData = "<PropertyData>" + "<IsPrivacyChanged>false</IsPrivacyChanged>" + "<IsValueChanged>true</IsValueChanged>" + "<Name>" + propertyName + "</Name>" + "<Privacy>NotSet</Privacy>" + "<Values><ValueData><Value xsi:type=\"xsd:string\">" + propertyValue + "</Value></ValueData></Values>" + "</PropertyData>"; $().SPServices({ operation: "ModifyUserPropertyByAccountName", async: false, webURL: "/", accountName: userId, newData: propertyData, completefunc: function (xData, Status) { var result = $(xData.responseXML); } }); }
3. Invoke updateUserProfile() Function
This function takes 3 parameters.
- userId: Your userID. The format is “domain\userId” for on-prem and “i:0#.f|membership|<federated ID>” for SharePoint Online.
- propertyName: The user profile property that needs to be changed
- propertyValue: The new user profile property value
Example:
updateUserProfile( "i:0#.f|membership|[email protected]", "Fax", "555 555 5555");
Note: The above code works but notice that you are passing a hardcoded userId.
To pass the current userId dynamically, we can use CSOM’s get_currentUser(). But since that’s based on the successful execution of ClientContext query, we need to “defer” invoking “updateUserProfile()” until we have received current userId. Therefore we’ll create a Deferred object as follows:
function getUserLogin() { var userLogin = $.Deferred(function () { var clientContext = new SP.ClientContext.get_current(); var user = clientContext.get_web().get_currentUser(); clientContext.load(user); clientContext.executeQueryAsync( function () { userLogin.resolve(user.get_loginName()); } , function () { userLogin.reject(args.get_message()); } ); }); return userLogin.promise(); }
Now when we invoke updateUserProfile(), it will execute getUserLogin() first, implying that the ClientContext query was successful :
getUserLogin().done(function (userId) { updateUserProfile(userId, "Fax", "555 555 5555"); });
4. Full working code
Steps to replicate the demo
- Copy the following code snippet and save it as a text file (.txt)
- Upload this text file anywhere on your SharePoint site (e.g. Site Assets). Remember its path.
- On the same SharePoint site, add/edit a page and insert a CEWP (Content Editor Web Part)
- On the web part properties of CEWP, add the path to the text file under “Content Link” section
- Click Ok, and save the page.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2013.01/jquery.SPServices-2013.01.min.js"></script> <script type="text/javascript"> //updateUserProfilePreFlight defers until getUserId() is "done" //then it invokes updateUserProfile function updateUserProfilePreFlight(){ getUserId().done(function (userId) { var propertyName = "Fax" var propertyValue = $("#Fax").val(); updateUserProfile(userId, propertyName, propertyValue); }); } //getUserLogin() uses CSOM to retrive current userId. function getUserId() { var userLogin = $.Deferred(function () { var clientContext = new SP.ClientContext.get_current(); var user = clientContext.get_web().get_currentUser(); clientContext.load(user); clientContext.executeQueryAsync( function () { userLogin.resolve(user.get_loginName()); } , function () { userLogin.reject(args.get_message()); } ); }); return userLogin.promise(); } //updateUserProfile updates the userprofile property function updateUserProfile(userId, propertyName, propertyValue) { var propertyData = "<PropertyData>" + "<IsPrivacyChanged>false</IsPrivacyChanged>" + "<IsValueChanged>true</IsValueChanged>" + "<Name>" + propertyName + "</Name>" + "<Privacy>NotSet</Privacy>" + "<Values><ValueData><Value xsi:type=\"xsd:string\">" + propertyValue + "</Value></ValueData></Values>" + "</PropertyData>"; $().SPServices({ operation: "ModifyUserPropertyByAccountName", async: false, webURL: "/", accountName: userId, newData: propertyData, completefunc: function (xData, Status) { var result = $(xData.responseXML); } }); } </script> <input id="Fax" type="text" placeholder="Update Fax" /> <input onclick="updateUserProfilePreFlight()" type="button" value="Update" />
Note
- You can only edit the user profile properties that are editable (unlocked) on your MySite. Certain fields like department are usually locked for editing as per company policy
Hi there, does this work with on-premises SP2013?
Miikka:
This should work exactly the same on premises.
M.
Hi Marc,
Can you help me in updating custom user profile property of type – String (Multi Value)
mapped to term store.
I’m able to update it using single term, but when I pass multi term it gives 500 error.
I tried below options:
1) Term1,Term2
2) Term1;Term2
3) Term1|Term2
4) TermName1;#GUID1,TermName2;#GUID2
But, no luck.
Could you please suggest?
Whenever i try to update the property , it says “the specified property does not exist” but in user profile property exist and modifiable also