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
Gary & Marc,
Love the post, love the writing style.
Is it possible to change other’s user profile ? I tried it, but I am getting an “Attempted to perform an unauthorized operation.” exception.
Is there a way to sort this out ?
I also tried this using .NET code (connecting to SharePoint Online) and passing global admin credentials. The GetUserPropertyByAccountName works for different users, but the ModifyUserPropertyByAccountName only works for the current user
Thanks,
Ricardo:
All SOAP calls are performed with the current user’s credentials. If they can’t perform the operation via the UI, they can’t perform it via the Web Services.
M.
Ricardo:
Web Services *always* run under the current user’s permissions. If the user can’t perform the action through the UI, they can’t through the Web Services, either.
M.
Thanks for your prompt response.
If you don’t mind I have another question. I am trying this code in a sharepoint auto-hosted app using jquery (in a sharepoint-hosted app it works), but I am getting “Transport Error”, then what I do is to add this line:
jQuery.support.cors = true;
but still does not work, now I get “access denied”
Is there any way to work around this?
Ricardo:
You can’t just set jQuery.support.cors = true; the target app has to support it and allow it.
M.
Hey, sorry to bother you again. The above scenario works when calling the service via .net code and passing the fedauth cookies of the O365 global admin, and also when referencing the service via the Tenant Admin site collection. I will be trying to resolve this but using SPServices and jquery
Thanks,
Ricardo
Ricardo:
I’m not sure if you had a question? If you do, please post it in the SPServices discussions.
M.
Dear Anderson,
The below part of the code isn’t executing,pls help.
$().SPServices({
operation: “ModifyUserPropertyByAccountName”,
async: false,
webURL: “/”,
accountName: userId,
newData: propertyData,
completefunc: function (xData, Status) {
var result = $(xData.responseXML);
}
});
Thanks,
Amar
Amar:
It’s hard to say what the issue is. It could be anything from a lack of permissions to bad data in the variables. I think you’re going to have to do some debugging.
M.
was getting error in status
completefunc: function (xData, Status)
when i was refering jquery.SPServices-2014.01.js
but succeeded when i referred jquery.SPServices-2013.01.min.js
2013 version is working
I’d be interested to know what was causing the problem if you were able to spot it. Best to post questions about SPServices on the SPServices site at Codeplex, as it’s easier to share code there.
M.
Dear Marc,
Thanks a lot for this wonderful workaround.
couldn’t find the bug exactly! but when i tried the operation “ModifyUserPropertyByAccountName” through 2014 version, the property was not updated.
but when i tried with 2013 version the property got updated.
Hello,
I have a custom user profile property of type – String (Multi Value)
I have a termset mapped to this property.
Now, I want to update this user profile property.
If I have a single term selected, then it works. But, if returns error – 500 if I try to update property value with multiple terms.
I tried below options:
Term1,Term2
Term2;Term2
[{ “Id”: “6d953327-2026-4f25-b4a6-fdb8f61523be”, “Name”: “Term1” }, { “Id”: “f9a09db7-998d-42e8-a369-91c9ed0fa68b”, “Name”: “Term2” }]
But, no luck.
Could you please suggest?
I have the exact same issue..
Help anyone? :)
Hi i also have the same issue, were you guys able to resolve it.
Hey Marc,
I’m a big an of your SPServices because I realize the value it brought to MOSS when there were no CSOM or REST.
Now I’m using it in O365 to read certain user properties like Office Location,JobTitle etc. for the current logged in user.
But it returns an empty string for Job Title and Office Location properties.
I think I’m using wrong Internal names for these properties.
Anyway you could help ?
ANkit:
Why don’t you post your code over on the SPServices Codeplex discussions? I’m sure we can muddle through it.
M.
Do you have a sample to create as well ? this would be great.
Mostafa:
Do you mean create a User Profile property? I don’t think we can do that client side.
M.
I Have this error :
“Server was unable to process request. —> Attempted to perform an unauthorized operation.” when trying to update a field (I have tried Fax,SPS-MUILanguages and SPS-ContentLanguages) Any idea why ? Thanks
Rene:
It sounds like a permissions issue to me. If you can’t do it through the UI, you can’t do it with code.
M.
Hi Marc, do you know if SPServices work with Nintex forms in SharePoint Online? Thanks
KK:
Nintex forms generate an entirely different set of markup that I’ve never even looked at, so no.
M.
Thanks Marc