22

I am trying to create a form for a SharePoint Hosted app that will allow users to request a teamsite. The form writes to a list that is contained in the SharePoint site collection, from which a timer job will read and complete the teamsite provisioning process. The list I am updating contains vital 'User and Group', 'Choice', and 'URL' fields and I am having difficulty getting my REST post to work.

When I run this code, I get a 400 error with this JSON reponse:

{"error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"A 'PrimitiveValue' node with non-null value was found when trying to read the value of a navigation property; however, a 'StartArray' node, a 'StartObject' node, or a 'PrimitiveValue' node with null value was expected."}}} Bad Request

I have not been able to find any examples online of non-text fields being updated via REST services, so if anyone could provide samples or point me to good sources of information I would greatly appreciate it!

function CreateTeamsite() {

    var url = _spPageContextInfo.siteAbsoluteUrl;
    teamsiteValues = {
        //SP.Data.Teamsite_x0020_ListListItem
        "__metadata": { "type": "SP.Data.Teamsite_x0020_ListListItem"},
        //"__metadata": { "type": "SP.Data." + listName.charAt(0).toUpperCase() + listName.slice(1) + "ListItem" },
        "Title": $('input[id=ctl00_PlaceHolderMain_txt_name]').val(),
        "BusinessUnit": $("#sel_bu option:selected").text(),
        "Description_x002f_Purpose":"test", // $('input[id=ctl00_PlaceHolderMain_txt_purpose]').val(),
        "Members": peoplePicker_Members.GetAllUserKeys(),
        "SecondaryOwner": peoplePicker_secondaryOwner.GetAllUserKeys(),
        "Viewers":  peoplePicker_Viewers.GetAllUserKeys(),
        "Function": $("#sel_function option:selected").text(),
        "SeoKeywords": "test", //$('input[id=ctl00_PlaceHolderMain_txt_keywords]').val(),
        "Language1": $('input[id=ctl00_PlaceHolderMain_txt_language]').val(), //need to add this to the form
        "PrimaryOwner": peoplePicker_secondaryOwner.GetAllUserKeys(), //TODO: get the logged in user's login id
        "TimeZone1": $("#sel_timezone option:selected").val(),
        "TypeofTeamsite": $("input[name=type]:checked").val(),
        "URL": $('input[id=ctl00_PlaceHolderMain_txt_Url]').val()

    };

    var outputstring = "Confirm and Submit<br />";

    for (var key in teamsiteValues) {
        if (teamsiteValues.hasOwnProperty(key)) {
            outputstring += key + " -> " + teamsiteValues[key] + '<br />';
        }
    }

    $('#confirm').html(outputstring);

    submitTeamsite();

}

function submitTeamsite()
{
    var url = _spPageContextInfo.siteAbsoluteUrl;
    //var url = "http://teams.cce.com"; //TODO: pull this value from configuration later
    $.ajax({
        url: url + "/_api/web/lists/getbytitle('" + listName + "')/items",
        type: "POST",
        contentType: "application/json;odata=verbose",
        data: JSON.stringify(teamsiteValues),
        headers: {
            "Accept": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
        },
        success: function () { $('#message').text("Teamsite successfully submitted.");
        },
        error: function (jqXHR, textStatus, errorThrown) { $('#message').text("Update failed." + jqXHR.responseText + " " + errorThrown.toString()) }
    });

}

Update: I have found the answer to most of my question. Regarding the URL field, that is passed in a JavaScript object with Description and URL properties.

 "URL": {
            "Description": $('input[id=ctl00_PlaceHolderMain_txt_Url]').val(),
            "Url": "http://teams.cce.com/" + $('input[id=ctl00_PlaceHolderMain_txt_Url]').val()
        },

For the Choice field, just pass in the value and that works.

For the "person or group" field, it's not so clear. I get that we need to pass in a numeric id that corresponds to the user. I found that out though looking at the list item XML:

<d:PrimaryOwnerId m:type="Edm.Int32">2</d:PrimaryOwnerId> 

I am using a client-side people picker in the form app. Now, how do I get that ID from the people picker so that I can pass it to the REST query?

3
  • Can you please elaborate on what you mean by "For the Choice field, just pass in the value and that works." I am doing what I think is what you say, and I get a "Method not allowed" Jul 3, 2013 at 7:44
  • Ok, poking around some more got me the answer. For the choice field, your JSON should look like,{ ..., "columnNameValue":"newvalue",..} Jul 3, 2013 at 8:05
  • After further research, I have found that the appropriate Id to send to the list to update the people picker can be gotten though the following for the current user. var context = new SP.ClientContext.get_current(); var web = context.get_web(); var user = web.get_currentUser(); user.get_id(); However, for any other user, it seems to be impossible to get the actual user object in CSOM or JSOM. So for now I am storing the current user in the picker, and other users in textfields.
    – Mikel
    Jul 9, 2013 at 20:08

4 Answers 4

10

You need to write the ID to the field name as shown below.

Example: Field name = EmployeeName

You must write the user ID to EmployeeNameId

8

I have a complete article on this. I know that I am very late but it may help others when they will get stuck with this same problem.

CRUD Operation to List Using SharePoint 2013 Rest API

var data = {
    __metadata: { 'type': 'SP.Data.SpTutorialListItem' },
    Title: 'Some title',
    SpMultiline: 'Put here some multiline text. You can add here some rich text also',
    SpChoice: 'Choice 3',
    SpNumber: 5,
    SpCurrency: 34,
    SpDateTime: new Date().toISOString(),
    SpCheckBox: true,
    SpUrl: {
        __metadata: { "type": "SP.FieldUrlValue" },
        Url: "http://test.com",
        Description: "Url Description"
    },
    SpPersonId: 3,
    SpLookupId: 2
};

For people or group: you have to specify the ID of people or group. Another important thing, you have to append "Id" with the column's internal name. see my article for more details

For Choice: Just pass a string value which already exists in choices

For Hyperlink: you have to pass an object with three properties. see SpUrl in mine article.

5

I have resolved the issue. When you try to create/update list item just check the fields details of the list using the REST API. for an example I have created a List named TestList. Following is the field details:

  • Title: Text
  • TestCL1: Text
  • TextCL2: Text
  • TestCL3: People and Group

Now to check the field details you just add some dummy element in the List and check the details of the fields using the following REST API URL:


http://SITEURL/_vti_bin/client.svc/web/lists/getByTitle('TestList')/items

Now you will get following data in IE: enter image description here
Now check the above picture carefully, the userid needs to be saved in the TestCL3Id column not in the TestCL3. This is the reason of the error. Now check the following code:

  • Go To SiteAssets and create a folder Scripts
  • Add jquery-1.11.1.min.js and Script.js. Add the following code in the Scripts.js file:

//Auto Populate User and Group Field
function initializePeoplePicker(peoplePickerElementId) {
    // Create a schema to store picker properties, and set the properties.
    var schema = {};
    schema['PrincipalAccountType'] = 'User,DL,SecGroup,SPGroup';
    schema['SearchPrincipalSource'] = 15;
    schema['ResolvePrincipalSource'] = 15;
    schema['AllowMultipleValues'] = true;
    schema['MaximumEntitySuggestions'] = 50;
    schema['Width'] = '280px';

    // Render and initialize the picker. 
    // Pass the ID of the DOM element that contains the picker, an array of initial
    // PickerEntity objects to set the picker value, and a schema that defines
    // picker properties.
    this.SPClientPeoplePicker_InitStandaloneControlWrapper(peoplePickerElementId, null, schema);
}


$(document).ready(function () {
    initializePeoplePicker('peoplePickerDiv');
});

function fnCreateItem()
{
    getUserInfo();
}
// Render and initialize the client-side People Picker.

// Query the picker for user information.
function getUserInfo() {
    // Get the people picker object from the page.
    var peoplePicker = this.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;
    // Get information about all users.
    var users = peoplePicker.GetAllUserInfo();
      // Get the first user's ID by using the login name.
    getUserId(users[0].Key);
}

// Get the user ID.
function getUserId(loginName) {
    var context = new SP.ClientContext.get_current();
    this.user = context.get_web().ensureUser(loginName);
    context.load(this.user);
    context.executeQueryAsync(
         Function.createDelegate(null, ensureUserSuccess), 
         Function.createDelegate(null, onFail)
    );
}

function ensureUserSuccess() {
    addListItem('http://win-og78bueinb9','TestList',this.user.get_id());
}

function onFail(sender, args) {
    alert('Query failed. Error: ' + args.get_message());
}


// Adding a list item with the metadata provided
function addListItem(url, listname,userid) {
    alert(userid);
    // Prepping our update
    var item = $.extend({
        "__metadata": { "type": "SP.Data.TestListListItem"}
    }, {'Title': $('#txtTitle').val(),'TestCL1': $('#txtTestCL1').val(),'TestCL2': $('#txtTestCL2').val(),'TestCL3Id': userid });
    // Executing our add
    $.ajax({
        url: url + "/_api/web/lists/getbytitle('" + listname + "')/items",
        type: "POST",
        contentType: "application/json;odata=verbose",
        data: JSON.stringify(item),
        headers: {
            "Accept": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
        },
        success: function (data) {
            alert('OK');
        },
        error: function (data) {
            alert('FAILED');
        }
    });
}

  • Now Create a WebPart page and add a content Editor WebPart and add the following code:

<script src="/SiteAssets/Scripts/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="/_layouts/15/clienttemplates.js" type="text/javascript"></script>
<script src="/_layouts/15/clientforms.js" type="text/javascript"></script>
<script src="/_layouts/15/clientpeoplepicker.js" type="text/javascript"></script>
<script src="/_layouts/15/autofill.js" type="text/javascript"></script>
<script src="/_layouts/15/sp.js" type="text/javascript"></script>
<script src="/_layouts/15/sp.runtime.js" type="text/javascript">
</script><script src="/_layouts/15/sp.core.js" type="text/javascript"></script>
<script src="/SiteAssets/Scripts/Script2.js" type="text/javascript"></script> 
<table> 
   <tbody>
      <tr>
         <td>Title:</td>
         <td>
            <input id="txtTitle" type="text"/>
         </td>
      </tr> 
      <tr>
         <td>Test CL1:</td>
         <td>
            <input id="txtTestCL1" type="text"/>
         </td>
      </tr> 
      <tr>
         <td>Test CL2:</td>
         <td>
            <input id="txtTestCL2" type="text"/>
         </td>
      </tr> 
      <tr>
         <td>Test CL3:</td>
         <td>
            <div id="peoplePickerDiv"> </div>
         </td>
      </tr> 
      <tr>
         <td colspan="2">
            <input onclick="fnCreateItem()" type="button" value="Create Item"/>
         </td>
      </tr> 
   </tbody>
</table>

This will create the following UI: enter image description here
- Add some data in the fields. You can see the Test CL3 field is getting autopopulated. enter image description here
- Click Create Item - The Item should be created.

Reference: http://msdn.microsoft.com/en-us/library/jj713593.aspx. Be careful when you are adding the reference.

Enjoy!!!

0

it would be

"Person": {
    "results": "[1]"
}

Your Answer

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

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