5

I am trying to use REST API approach in javascript to update a sharepoint list item where I have an id. So I use GET and POST to create records, but per MSDN article it looks like the way to do this is combination of MERGE and POST but I am having trouble connecting the dots. So it appears under MERGE and PUT Operations section there is an entity that gets created in a basic ajax/POST method, and then the update utilizes the same approach to update, but I am trying to find an approach that will allow me to update without the post method....so this may be straight forward but....

appreciate any help with this as always

UPDATE: so I probably need to ellaborate on this a bit:

I use REST to pull all the time because for whatever reason in my environment, it seems to be consistently the quickest returning data between it, COM and SPServices. Been using this type of approach:

getData(thisUrl, thisCallback);

function getData(url, callback) {
        try {
    var request = new Sys.Net.WebRequest();
    request.set_httpVerb("GET");
    request.set_url(gridUrl);
    request.get_headers()["Accept"] = "application/json";
    request.add_completed(callback);
    request.invoke();
} catch (e) {
    alert(e.message); 
}

}

function thisCallback(response, eventArgs) {
var resultData = JSON.parse(response.get_responseData());
for (var i = 0; i < resultData.d.results.length;i++) {
   // get my data and process 
}
}

}

this works awesome so I just wanted to explore the other basic CRUD operations. found this MSDN page: http://msdn.microsoft.com/en-us/library/ff798339.aspx

Example below works well for me for creating a new list item (taken from link):

var url = 'http://localhost/sites/sharepointlist/_vti_bin/listdata.svc/InventoryLocations';
var inventoryLocation = {};

// Insert a new Part location.
inventoryLocation.PartId = $('#hidPartId').val();
inventoryLocation.BinNumber = $('#binText').val();
inventoryLocation.Quantity = $('#quantityText').val();

var body = Sys.Serialization.JavaScriptSerializer.serialize(inventoryLocation);

$.ajax({
         type: 'POST',
         url: url,
         contentType: 'application/json',
         processData: false,
         data: body,
         success: function () 
         {
           alert('Inventory Location Saved.');
         }
       });

so the next part I wanted to learn is the updating, which per this article seems to be a combination of MERGE and POST?:

var locationId = $('#hidLocationId').val();
var url = 'http://localhost/sites/sharepointlist/_vti_bin/listdata.svc/InventoryLocations';
var beforeSendFunction;
var inventoryLocationModifications = {};

// Update the existing Part location.
url = url + "(" + locationId + ")";
beforeSendFunction = function (xhr) 
{
  xhr.setRequestHeader("If-Match", inventoryLocation.__metadata.ETag);
  // Using MERGE so that the entire entity doesn't need to be sent over the wire. 
  xhr.setRequestHeader("X-HTTP-Method", 'MERGE');
}

inventoryLocationModifications.BinNumber = $('#binText').val();
inventoryLocationModifications.Quantity = $('#quantityText').val();

var body = Sys.Serialization.JavaScriptSerializer.serialize(inventoryLocationModifications);

$.ajax({
         type: 'POST',
         url: url,
         contentType: 'application/json',
         processData: false,
         beforeSend: beforeSendFunction,
         data: body,
         success: function () 
         {
           alert('Inventory Location Saved.');
         }
       });

so this i can get to work if I first create the item, then turn around and update the item using this exact approach, but I am wondering how you would take this approach to just update an item that already exists? In order to use the above do I have to create the item first to get the inventoryLocation so the ._metadata.ETag doesn't error? Is there another way?

I understand I am probably just lacking some context on this, I just haven't been able to find anything yet that helps me get it.....always appreciated!

1 Answer 1

6

I'm not exactly sure what which aspect is confusing your so I will break down the process into some steps. Let's imagine we have a custom list titled Issue Tracker with the following definition:

Fields:

Id                  (number) the default field
Title               (text) the default field
Problem Description (text)
Products            (multiselect choice) checkboxes, users can select multiple values
Status              (choice) radio buttons, users can only select one value
Assigned To         (person) only on SP user/group allowed in field
Following           (person) allows multiple SP users.

This will generate an entity that looks like this:

{
    "__metadata": {
        "uri": "https://server.domain.com/site/_vti_bin/ListData.svc/IssueTracker(1)",
        "etag": "W/\"17\"",
        "type": "Microsoft.SharePoint.DataService.IssueTrackerItem"
    },
    "id": 1,
    "Title": "Text of my title",
    "Description": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
    "Status": {
        "__deferred": {
            "uri": "https://server.domain.com/site/_vti_bin/ListData.svc/IssueTracker(1)/Product"
        }
    },
    "StatusId": 2,
    "AssignedTo": {
        "__deferred": {
            "uri": "https://server.domain.com/site/_vti_bin/ListData.svc/IssueTracker(1)/AssignedTo(291)/OwnersGroup"
        }
    },
    "Following": {
        "results": []
    },
    "Products": {
        "results": [
            {
                "__metadata": {
                    "uri": "https://server.domain.com/site/_vti_bin/ListData.svc/IssueTrackerProducts('My%20Product%20Name')",
                    "type": "Microsoft.SharePoint.DataService.IssueTrackerProductsValue"
                },
                "Value": "My Product Name"
            }
        ]
    }
}

I do not update the status or assigned to fields directly but instead I will set just set the StatusId and AssignedToId fields to their appropriate values. AssignedToId is of course the value of the SP user's ID from the UserInformationList.

The other fields that are multiselect (products and following) are more complex and need to be updated in a separate transaction or in a batch iof you are using a lib like DataJS.

If all I want to do is update one of the fields with a simple properts I just send the new values in my entity to the server as aPOST with the following headers:

Content-Type: application/json
If-Match: W/"17"
X-HTTP-Method: MERGE
Accept: application/json

to this URL:

https://server.domain.com/site/_vti_bin/ListData.svc/IssueTracker(1)

If I need to add a product to my item things are a bit more complex. These operations are additive. It will not replace the value only add a product called 'My Other Product Name' to the array.

{
    "Products": [
        {
            "__metadata": {
                "uri": "https://server.domain.com/site/_vti_bin/ListData.svc/IssueTrackerProducts('My%20Other%20Product%20Name')",
                "type": "Microsoft.SharePoint.DataService.IssueTrackerProductsValue"
            },
            "Value": "My Other Product Name"
        }
    ]
}

If I want to delete 1 or multiple items or clear the array I have to do it one by one.

To do that you send an HTTP DELETE to

https://server.domain.com/site/_vti_bin/ListData.svc/IssueTracker(1)/$links/Products('My%20Other%20Product%20Name');

And that would delete the My Other Product Name from the array. It's the same for multiselect fields of type person or group as well.

See my other threads:

Updating a multiselect field via REST API 2010

ListData.svc and Task Approval (there appears to be a bug in ListData.svc that does not allow you to modify a task when it is being watched by a work flow)

I have found updating complex fields to be such a pain using ListData.svc that in general I use the JavaScript Client Side Object Model to perform my update and create operations. But using the REST API I can manage concurrency more easily and it's easier to read list data.

6
  • ...wow thanks. one of the best answers I have gotten. thanks for all the info. I suppose my question was pretty vague in context, but context is also a part of what I am learning. The overall syntax as an example is what confuses me basically due to I was trying to learn this approach from one MSDN page I support. Will add more to my question.
    – Justin
    Jun 16, 2013 at 17:17
  • the last bit helps me huge because even though I will still pursue this just to learn, if the COM is easier for updating, then I will just go with that instead and use REST to pull. Though I have found adding new fields with ajax/POST pretty good too...so is there a reason, like something i just haven't run into that this method becomes a pain? thanks again. appreciated!
    – Justin
    Jun 16, 2013 at 17:19
  • Do you mean that updating via ListData.svc becomes a pain? Only when I am dealing with multiselect fields. If you mean when using REST for read and JSOM for update becomes a pain, not that I have found. I use Kendo UI and the MVVM pattern in my pages and I just keep an array of the fields that are changed, do a quick GET selecting only a single, small field to compare the etags and then do my update or show the user a warning. Jun 16, 2013 at 17:34
  • For my updates I use a custom method that I just pass an array of objects that contain the field name and value pairs. Internally it uses the JSOM to update the item. So it's all pretty easy. Jun 16, 2013 at 17:38
  • 1
    Really it is all about the multiselect fields. If you have none of them in a list item, then it's likely easier to use REST. It's only the multiselects that make it harder. I don't want to have to increment the version number 3 times just to update one field... Jun 16, 2013 at 17:55

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.