I have a custom angular JS form for my list in a SP hosted app and i am facing a challenge when i need to set the user field value due to JS async been... out of sync. So specifically when the user clicks the save button i must;

  1. Get Values from people picker - work ok
  2. Ensure User (because they might have never accessed the site) - if the user is not the current user then the ID isnt returned
  3. Create list item setting the users as value to a user field - user objects not processed yet when the list item create code is executed

When the following code completes usually there are no users in the field, or if there are, its just one.

    $scope.saveEvent = function () {
    if ($scope.event.inviteOnly === 1) {
        var peoplePicker = window.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;
        var usersVal = peoplePicker.GetAllUserInfo();
        for (var i = 0; i < usersVal.length; i++) {

            var ctx = SP.ClientContext.get_current();
            var usr = ctx.get_web().ensureUser(usersVal[i].Key);
            ctx.executeQueryAsync(function () {
                var val = new SP.FieldUserValue();
                function () {
                    console.log("failed to resolve user");

        if ($scope.event.attendees.length == usersVal.length) {

    $scope.createListItem = function () {
        var context = SP.ClientContext.get_current();
        var targetList = context.get_web().get_lists().getByTitle("Events");
        var itemCreate = new SP.ListItemCreationInformation();
        var newItem = targetList.addItem(itemCreate);
        newItem.set_item('Title', $scope.event.title);
        newItem.set_item('EventDate', new Date($scope.event.date));
        newItem.set_item('EventDepartment', $scope.event.department);
        newItem.set_item('EventLocation', $scope.event.location);
        newItem.set_item('EventOtherInfo', $scope.event.otherInfo);
        newItem.set_item('EventTravelInfo', $scope.event.travelInfo);
        newItem.set_item('EventType', $scope.event.eventType);
        newItem.set_item('EventDescription', $scope.event.description);
        newItem.set_item('EventRegistrationRequired', $scope.event.inviteOnly);
        newItem.set_item('EventAttendees', $scope.event.attendees);
        newItem.set_item('EventPicture', $scope.event.picture);
        var questionHtml = '<ul>';
        for (var i = 0; i < $scope.event.questions.length; i++) {
            questionHtml += '<li>' + $scope.event.questions[i].value + '</li>';
        questionHtml += '</ul>';
        newItem.set_item('EventQuestions', questionHtml);

        context.executeQueryAsync(function () {
            if ($scope.event.inviteOnly == 1 && $scope.event.attendees && $scope.event.attendees.length > 0) {
                for (var j = 0; j < $scope.event.attendees.length; j++) {
                    var user = context.get_web()

                    var collRoleDefinitionBinding = SP.RoleDefinitionBindingCollection.newObject(context);

                    newItem.get_roleAssignments().add(user, collRoleDefinitionBinding);
                context.executeQueryAsync(null, null);
            function (sender, args) {
                alert("Failed to save event: " + args.get_message());

1 Answer 1


Your createListItem() is getting called before attendees is built. You have two options -

  1. Build a promises array and push one promise for each user in usersVal. Resolve each promise inside your ensure user callback. And finally, wait for all promises to be completed before you invoke $scope.createListItem()
  2. Instead of using CSOM to do ensure user you can use REST API for EnsureUser and set async to false in ajax settings to execute them synchronously

I would recommend first option since it won't block the UI.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.